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 watch
or 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.
Anyway, here’s wonderwall here are a few command lines that spent a lot of time in my history
.
The absolute basics – best run from the root of your project (topmost folder with a pom.xml
):
$ 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 compile
:
$ mvn -pl=moduleA compile
The -pl
(--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 -am
(--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 compile
s without 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
Or
$ 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 someTest
in 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 Main.java
/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
yasnippets
I use yasnippet
and 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 current-snippet-table
.
While this isn’t very good content, and pretty anti-climactic I fixed the issue I ran into by re-installing yasnippet
and 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 yasnippet
and 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.