Code generation with annotation processors

by: Ethan McCue

Java does not allow annotation processors to affect the source or bytecode of classes you have written, only generate new classes.

In Java 17, there is a clever way around this restriction though.

Lets say you want to make an annotation processor that adds a toJson method to a class based on some automated set of rules.

@AutoToJson
public record BasicThing(String color, String size) {}

What you can do is generate an interface with a predictable name

interface BasicThingToJson {}

Make it "sealed", so that only the class you want to can implement it

sealed interface BasicThingToJson permits BasicThing {}

And then inside of the interface you can add a default method, in which it is safe to assume that the only possible class that implements the interface is the class you want to

sealed interface BasicThingToJson permits BasicThing {
    default JSON toJson() {
        // totally safe
        var self = (BasicThing) this;
        var jsonObject = new JsonObject();
        jsonObject.set("color", self.color());
        jsonObject.set("size", self.size());
        return jsonObject;
    }
}

And then all your user has to do is

  1. Annotate their class
  2. Implement the interface that will be generated (its kinda circular, but it works out)
@AutoToJson
public record BasicThing(String color, String size) implements BasicThingToJson {}

And then boom, their class has been "enriched" in whatever way you want.

var basicThing = new BasicThing("red", "small");
var json = basicThing.toJson();

<- Index