tl;dr - I had to use a slightly modified indentation setup for
java-mode to get close to the IntelliJ Java indentation scheme while doing some Java development. I also had to run Maven (
mvn) lots from the command line so I’ve included some tips on that. If you hate unnecessary rambling, jump to the elisp code
Generally, working with the Java programming language is not my first choice, but sometimes when money is involved I absolutely ignore my first choices. Recently while working with a rather large, corporate client’s codebase which was (as you might have guessed) in Java, I needed to find a way to use my beloved [Emacs][emacs] (Emacs has it’s own wiki) with the project I was working on. This post is a bit of a mishmash of the things I found I needed to change to get some reasonable looking auto-indented code to work.
Unfortunately, this is not a guide on how to use Emacs to write & debug java as easily as you might in something like IntelliJ with a tool like The Java Development Environment for Emacs, mostly because I didn’t bother with it. I did my building & running from the commandline, using Maven (
mvn) painfully manually (and with some
git hooks) from the command line. I will, however, leave some tips on how to run
mvn painfully from the command line (even though you really shouldn’t).
This also won’t be a diatribe on why I eschew IDEs and/or Java, let’s keep things productive. One more time for clarity – you should absolutely probably use an IDE, in previous positions I’ve even run emacs and IntelliJ side by side, popping into IntelliJ whenever I needed to perform builds. There are also likely better ways to integrate Emacs and Java that I’m not going to cover at all. If you’re going to ignore all those warnings then continue on. A quick Q&A with myself before we get started:
Q: Why not just use emacs bindings in IDEA?
A: Emacs bindings != Emacs, there’s a whole ecosystem to replicate.
Q: Why not just run a terminal inside IDEA and run Emacs in there
A: This is a reasonable solution (I’ve done this in previous roles), but IIRC there’s some overlap keyboard shortcuts and it’s a bit unwieldly.
Q: But how will you get your jump-to-definition and X feature?
A: I won’t – easy find in file & find in project are good enough for me.
To IntelliJ/the community’s credit they’ve made it really easy for outside tools to work, so there are one or two packages that help with this:
None of these really worked for me as a solution (and I failed to look into the others) – I basically chose to stick with running
mvn in the terminal, and pairing it with tools like
entr as necessary.
Here’s the emacs code that works to get some decent (I updated this as I found things that didn’t match properly):
;; Java ;; use C-c C-o to set offset ;; use C-c C-s to show syntactic information (show the variable that needs to be set) (add-hook 'java-mode-hook (lambda () (setq c-default-style "java") (c-set-offset 'arglist-intro '+) (c-set-offset 'arglist-close '0) (c-set-offset 'case-label '+) (display-line-numbers-mode 1) (auto-complete-mode t) ))
You might be wondering why I have those notes there about using
C-c C-o to set offsets and
C-c C-s to show syntactic information – well they’re there because I used those two commands enough to try and figure out what looked good that I never wanted to forget again.
As mentioned earlier, you probably shouldn’t ever do this, but I did. By avoiding IntelliJ and JDEE (Java Development Environment for Emacs), I went the likely seldom traveled path of just running
mvn as necessary while doing my development. If you’re not at all familiar with
mvn, you might want to start with the 5 minute guide to maven, and then maybe read the 30 minute guide, AKA the getting started guide.
Maven has been around a very long time, and while it’s arguably managed it’s growth well, it’s pretty difficult to use intuitively from the command line. Never mind the way the configuration is laid out, and the concepts behind Maven and how they manifest in it’s usage and configuration, I’m going to leave it at the fact that there is almost no one who has ever remarked at how easy Maven was to get started with. Whether it’s the plugin system, the goals/phases, the XML soup, restrictive/prescribed file layout, and how all these pieces fit together, Maven is a fucking jungle. People are only happy with maven once they’ve spent years in that jungle. Again, to be fair, Maven is very old – comparing it to modern build systems is unfair, so I won’t.
here’s wonderwall here are a few command lines that spent a lot of time in my
The absolute basics – best run from the root of your project (topmost folder with a
$ mvn install
Build, package, install the package. This command does everything necessary to put a built JAR in your
~/.m2 (as specified by the
M2_ROOT environment variable).
$ mvn compile
This just compiles the project in the current directory – quicker than a full
install and a good way to find out if any of the monstrosity that the code you just wrote actually works.
Maven has a bunch of command line options, and most of the following is going to be us going through them.
Most maven projects are multi-module, so you normally have a folder structure like this:
your-enterprise-project/ └── moduleA ├── moduleB │ └── src ├── main └── resources │ ├── test │ └── ... other folders ... ├── pom.xml ├── ... other files ...
After writing some code that affects
moduleA, you probably want to avoid building
moduleB just to check if your code compiles. What you can run instead of a regular
$ mvn -pl=moduleA compile
--projects) argument actually restricts the projects that are allowed to run, and you can use that to limit the running projects/modules to
moduleA. What about if
moduleA depends on
moduleD (the D is for Dependency)? We’ll you’ll need to run:
$ mvn -pl=moduleA -am compile
The addition of
--also-makeIf) instructs maven to build the dependencies of the projects that are being built.
You’re going to want to
clean very often, if anything to avoid weird builds. You might immediately think to yourself “weird builds? what a vague way to put that” – and you’d be right, I’m being vague here because the amount of problems I ran into that just shouldn’t have happened due to running regular builds made me stop running
clean. Some things were expected, like work with Avro where classes were generated at build time based on specifications. I ended up just appending
clean for most things:
$ mvn clean compile
$ mvn clean test-compile
Became my go-tos. I won’t include
clean everywhere for the rest of this post, because theoretically
mvn should work just as well when it doesn’t clean everything out, but that’s definitely not the case.
Here’s a thing that you’d think was relatively simple but you’d almost certainly have to google search to find out how to do – run a single unit test:
$ mvn test -Dtest=<TheClassYouWant>#<the method you want>
If you’re in
moduleA/ (or have
-pl=moduleA set in the project root), and you wanted to run a method named
SomeClassUnitTest.java, you’d run:
$ mvn test -Dtest=SomeClassUnitTest#testSomething
And if you wanted to run the whole class (this time, we’ll pretend we’re in the project root):
$ mvn -pl=moduleA -am test -Dtest=SomeClassUnitTest
Turns out running a single integration test isn’t quite the same as running a single integration test. To run a single integration test, you’re going to need to use:
$ mvn -pl=moduleA -am integration-test -Dit.test=SomeClassIntTest#testSomethingsIntegration
Sometimes you just want to run
App.java from a given subproject without any fuss. For those times, use:
$ mvn -pl=<subproject> -am exec:java -Dmain.class="path.to.your.class.Here"
Spring Boot is the new (actually kinda old) hotness (where regular Spring Framework projis the old hotness) – it’s dominant in the landscape for Java applications in the enterprise. Sometimes you just want to run your spring boot application with maven, assuming you have the Spring Boot Maven Plugin installed – for that, use:
$ mvn spring-boot:run
And what about different spring profiles? Well the best way I found was to just use the
SPRING_PROFILES_ACTIVE environment variable:
$ SPRING_PROFILES_ACTIVE=production mvn spring-boot:run
Let’s say you
mvn install install your way to a working JAR (which lands in the
target directory) what about when you want to run that JAR, with some overrides here and there?
$ java -jar /path/to/your/project.jar --spring.profiles.active=production --other.options=str --another.option=1
auto-complete, and for the longest time, my java development was less productive than normally afforded by these plugins due to an error about a
void function definition being missing for the
While this isn’t very good content, and pretty anti-climactic I fixed the issue I ran into by re-installing
auto-complete, and disabled some custom setup code I had in
~/.emacs. Maybe this section shouldn’t even be here, but if you’re not using
auto-complete you should start – it’s very useful, especially in Java land.
Thanks for stopping by – hopefully you enjoyed this post more than I enjoy writing Java code.