Search code examples
mavencode-generationmaven-mojo

maven mojo for reading app classes and generating java


I want to write a maven plugin which will explore the classpath of my application at build time, search for classes with a certain annotation, and generate some java code adding utilities for these classes, which should get compiled in the JAR of the application.

So I wrote a mojo, inheriting from AbstractMojo, and getting the project through:

@Parameter(defaultValue = "${project}", readonly = true, required = true)
private MavenProject project;

I have most of the code, and my mojo does get execute, but I'm having trouble inserting my mojo at right build phase.

If I plug it like that:

@Mojo(name = "generate", defaultPhase = LifecyclePhase.GENERATE_SOURCES,
      requiresDependencyResolution = ResolutionScope.COMPILE)

then the java code which I generate is compiled in the JAR file.

Note that I use project.addCompileSourceRoot to register the output folder.

But that isn't enough for me because it's too early in the build: I cannot read the classpath and find the classes from my project. I think they're not compiled yet.

I search for classes like so:

        final List<URL> urls = List.ofAll(project.getCompileClasspathElements())
                .map(element -> Try.of(() -> new File(element).toURI().toURL()).get());
        final URLClassLoader classLoader = new URLClassLoader(urls.toJavaList().toArray(new URL[0]), Thread.currentThread().getContextClassLoader());
        final Set<Class<?>> entities = HashSet.ofAll(new Reflections(classLoader).getTypesAnnotatedWith(MyAnnotation.class));

(I'm using vavr but you get the gist in any case)

So, by plugging my code at the GENERATE_SOURCES phase, this code doesn't work and I don't find any classes.

However, if I plug my mojo at the PROCESS_CLASSES phase:

@Mojo(name = "generate", defaultPhase = LifecyclePhase.PROCESS_CLASSES,
    requiresDependencyResolution = ResolutionScope.COMPILE)

Then my classes are found, I can access the rest of the code from the application, but the code that I generate is not taken into account in the build, despite using addCompileSourceRoot.

How do I get both features working at the same time: ability to explore code from the rest of the application and ability to generate code which will be compiled with the rest of the JAR?

I guess a possible answer would be "you can't", but as far as I can tell, querydsl and immmutables are doing it (I tried reading their source but couldn't find the relevant code).


Solution

  • So @khmarbaise was right, what I wanted was not a maven mojo, but rather a maven annotation processor.

    I found that this walkthrough was very helpful in creating one, and also this stackoverflow answer came in handy.