Backend Development 8 min read

Injecting Jar Version into Java Components with Insertable Annotation Processors

This article demonstrates how to create a custom insertable annotation processor in Java that automatically injects the jar version into component constants at compile time, enabling Prometheus monitoring of version usage without manual updates.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Injecting Jar Version into Java Components with Insertable Annotation Processors

Insertable annotation processors, mentioned briefly in "Understanding the Java Virtual Machine," are explored through a practical scenario where a company provides a suite of Java utility modules packaged as JARs and needs to monitor the usage of each version via Prometheus.

The naive solution of manually writing version constants in each component is cumbersome, prompting the question of whether the version can be injected automatically during the Gradle build, similar to Lombok's compile‑time code generation.

To achieve this, a custom annotation @TrisceliVersion is defined and an annotation processor extending AbstractProcessor is implemented. The processor obtains the AST node for each annotated field, verifies it is a String , and replaces its initializer with the value returned by getVersion() , which reads the version (here simplified to a fixed string).

@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.FIELD})
public @interface TrisceliVersion {}
public class TrisceliVersionProcessor extends AbstractProcessor {
    private JavacTrees javacTrees;
    private TreeMaker treeMaker;
    private ProcessingEnvironment processingEnv;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        this.processingEnv = processingEnv;
        this.javacTrees = JavacTrees.instance(processingEnv);
        Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(context);
    }

    @Override
    public Set
getSupportedAnnotationTypes() {
        HashSet
set = new HashSet<>();
        set.add(TrisceliVersion.class.getName());
        return set;
    }

    @Override
    public boolean process(Set
annotations, RoundEnvironment roundEnv) {
        for (TypeElement t : annotations) {
            for (Element e : roundEnv.getElementsAnnotatedWith(t)) {
                JCTree.JCVariableDecl jcv = (JCTree.JCVariableDecl) javacTrees.getTree(e);
                String varType = jcv.vartype.type.toString();
                if (!"java.lang.String".equals(varType)) {
                    printErrorMessage(e, "Type '" + varType + "' is not supported.");
                }
                jcv.init = treeMaker.Literal(getVersion());
            }
        }
        return true;
    }

    private void printErrorMessage(Element e, String m) {
        processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, m, e);
    }

    private String getVersion() {
        return "v1.0.1"; // simplified for demo
    }
}

The processor must be discoverable via the SPI mechanism, requiring a META-INF/services/javax.annotation.processing.Processor file that lists the processor class.

After adding the processor to a test module and running gradle build , the generated bytecode contains the version constant populated automatically, eliminating the need for manual updates.

This example illustrates only a fraction of what insertable annotation processors can achieve; by manipulating the abstract syntax tree at compile time, developers can create powerful plugins that reduce boilerplate and enforce consistency across large Java codebases.

backendJavaGradlePrometheusannotation-processingLombokcompile-time
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.