Skip to content

Generate code

B. K. Oxley (binkley) edited this page Aug 14, 2024 · 8 revisions
Coffee grinder

Generate code

When sensible, prefer to generate rather than write code. Here's why:

  • Intelligent laziness is a virtue.
  • Tools always work, unless they have bugs, and you can fix bugs. Programmers make typos, and fixing typos is a challenge when not obvious. Worse are _ thinkos_; code generation does not " think", so is immune to this problem.
  • Generated code does not need code review, only the source input for generation needs review, and this is usually shorter and easier to understand. Only your hand-written code needs review.
  • Generated code is usually ignored by tooling such as linting or code coverage (and there are simple workarounds when this is not the case). Your hand-written code needs tooling to shift problems left.

Note that many features for which in Java one would use code generation (eg, Lombok's @Getter or @ToString), can be built-in language features in other languages such as Kotlin or Scala (eg, properties or data classes).

Lombok

Lombok is by far the most popular tool in Java for code generation. Lombok is an annotation processor, that is, a library (jar) which cooperates with the Java compiler. (An introductory guide to annotations and annotation processors is a good article if you'd like to read more on how annotation processing works.)

Lombok covers many common use cases, does not have runtime dependencies, there are plugins for popular IDEs that understand Lombok's code generation, and has tooling integration for JaCoCo's output code coverage (see below).

Do note though, Lombok is not a panacea, and has detractors. For example, to generate code as an annotation processor, it in places relies on internal JDK APIs, though the situation has improved as the JDK exposes those APIs in portable ways.

Leverage Lombok to tweak code coverage

Be sparing in disabling code coverage! JaCoCo knows about Lombok's @Generated, and will ignore annotated code.

A typical use is for the main() method in a framework such as Spring Boot or Micronaut. For a command-line program, you will want to test your main().

Do note that Lombok reflects on internal features of the JDK. If you have issues, for Maven: use in your project the --add-opens java.base/java.lang=ALL-UNNAMED example from .mvn/jvm.config, and look to address these. The solutions in the project are a "workaround" assuming Java 21. This is a two-edged sword: as the JVM improves access controls, you may find, especially dependencies, that there are times you want deep reflection.

Lombok configuration

Configure Lombok in src/lombok.config rather than the project root or a separate config directory. At a minimum:

config.stopBubbling=true
lombok.addLombokGeneratedAnnotation=true
lombok.anyConstructor.addConstructorProperties=true
lombok.extern.findbugs.addSuppressFBWarnings=true

Lines:

  1. stopBubbling tells Lombok that there are no more configuration files higher in the directory tree.
  2. addLombokGeneratedAnnotation helps JaCoCo ignore code generated by Lombok.
  3. addConstructorProperties helps JSON/XML frameworks such as Jackson (this may not be relevant for your project, but is generally harmless, so the benefit comes for free).
  4. addSuppressFBWarnings helps SpotBugs ignore code generated by Lombok.

More examples

Tips

TODO: Placeholder section

Going further

TODO: Placeholder section

Clone this wiki locally