When I Gave Up IntelliJ for Lent

05 Jan 2025

I know that it’s a controversial opinion among programmers under 50, but I actually like Java.

All of the newer language features, like streams, records and local variable type inference, make writing Java feel as nice as any other modern language. The JVM is amazing and there are so many high-quality open source libraries available (h/t Dropwizard)

However, working with Java can be very annoying. There are basically only two options: stay in the warm, fuzzy IDE, or learn everything about build systems, Javadoc and editor configuration to be able to work from the terminal.

Many years ago, I was frustrated by how magical and complicated building Java projects felt, so I decided to give up IntelliJ for Lent. That left me with vim and Gradle in a terminal.

The first hurdle was understanding how to navigate the codebase. This was before LSPs, but it was easy enough to figure out with ctags and grep. (These days things are pretty good with jdtls in Neovim.) The hard part was understanding third party libraries.

A lot documentation is published online, but it can be hard to find it for specific dependency versions. At any rate, doing that is much slower than the “go to definition” functionality that IDEs provide. So I figured that I could use Gradle to do something similar.

It turned out that getting the Javadoc (and sources) was straightforward using the idea plugin:

idea {
  module {
    downloadJavadoc = true
    downloadSources = true
  }
}

After that runs, the dependency code and documentation are downloaded to the ~/.gradle/caches directory:

~/.gradle/caches$ find . -name 'commons-io*.jar'
./modules-2/files-2.1/commons-io/commons-io/2.18.0/44084ef756763795b31c578403dd028ff4a22950/commons-io-2.18.0.jar
./modules-2/files-2.1/commons-io/commons-io/2.18.0/e2281d62ae24acd84de1ef7273e70bfb38c75658/commons-io-2.18.0-javadoc.jar
./modules-2/files-2.1/commons-io/commons-io/2.18.0/9ab23bf96cc41b731cb123fbee97198f901af68e/commons-io-2.18.0-sources.jar

The Javadoc artifact contains a full static website, so all that you have to do is extract it and load up index.html in the browser:

~/Desktop$ mkdir commons-io
~/Desktop$ cd commons-io/
~/Desktop/commons-io$ jar xf ../commons-io-2.18.0-javadoc.jar
~/Desktop/commons-io$ tree | head -25
.
├── allclasses-index.html
├── allpackages-index.html
├── constant-values.html
├── deprecated-list.html
├── element-list
├── help-doc.html
├── index-all.html
├── index.html
├── jquery-ui.overrides.css
├── legal
│   ├── ADDITIONAL_LICENSE_INFO
│   ├── ASSEMBLY_EXCEPTION
│   ├── jquery.md
│   ├── jqueryUI.md
│   └── LICENSE
├── member-search-index.js
├── META-INF
│   ├── MANIFEST.MF
│   └── maven
│       └── commons-io
│           └── commons-io
│               ├── pom.properties
│               └── pom.xml
├── module-search-index.js
...

It was annoying to do that every time that I wanted to look at documentation, let alone navigate from simple class name reference in code to the right place, so I put together some simple tooling.

I wanted something similar to pydoc for Python, and it had to do three main things:

  • Extract - Extract the documentation / sources into a common place.
  • Index - Parse documentation for class names and build an index.
  • Search - Match a query against the list of class names and return documentation.

The tool creates a root directory, walks the local repository to find *-sources.jar and *-javadoc.jar artifacts, then extracts them under ${root}/sources/${artifact-name} and ${root}/javadoc/${artifact-name}. At this point, it’s easy to explore the documentation top-down if you know the artifact name, but it’s hard to find a specific class.

Fortunately there are pages like allclasses-index.html that list all of the class names and link to their docs, (though naming isn’t always consistent.) The tool looks for these files, then builds a mapping of class name, (really Maven coordinates), to the documentation file path. This mapping gets dumped to a JSON file under the root directory.

Finally, the tool can search that JSON file using simple keyword matching and regular expressions to output matching class names along with their Javadoc and sources.

I put this together and called it jdoc. It’s not very complicated - only about 250 lines of code. After Javadoc and sources are downloaded via the build tool, just run jdoc --index, and search by passing one or more patterns to it:

$ jdoc XmlStreamWriter
   name: org.apache.commons.io.output.XmlStreamWriter
    jar: commons-io-2.18.0-javadoc.jar
javadoc: file:///home/greg-brandt/jdoc/javadoc/commons-io-2.18.0-javadoc.jar/org/apache/commons/io/output/XmlStreamWriter.html
 source: file:///home/greg-brandt/jdoc/sources/commons-io-2.18.0-sources.jar/org/apache/commons/io/output/XmlStreamWriter.java

   name: org.apache.commons.io.output.XmlStreamWriter.Builder
    jar: commons-io-2.18.0-javadoc.jar
javadoc: file:///home/greg-brandt/jdoc/javadoc/commons-io-2.18.0-javadoc.jar/org/apache/commons/io/output/XmlStreamWriter.Builder.html
 source: file:///home/greg-brandt/jdoc/sources/commons-io-2.18.0-sources.jar/org/apache/commons/io/output/XmlStreamWriter.Builder.java

Also here is my favorite vim keybinding for it, which uses the -e flag to do exact class name match, and targets the token under the cursor:

nnoremap <leader>j :execute '!jdoc -e ' . expand('<cword>')<CR>

You can download the tool if you’re interested here: https://github.com/brandtg/jdoc