Maven插件GENERATE_SOURCES阶段如何获取项目未编译类?
Great question—this is a super common pain point when building code-gen Maven plugins that need to peek at the project's own classes before they're even compiled. Let's walk through a few practical, production-ready solutions:
1. Parse Source Files Directly (No ClassLoader Required)
If you only need to inspect class structure, annotations, method signatures, or field definitions (the most common use case for code generation), you don't need to load compiled classes at all. Instead, parse the raw Java source files using a dedicated library:
- JavaParser: A lightweight, intuitive library that lets you traverse Java Abstract Syntax Trees (ASTs) without compiling code. You can extract annotations, check class hierarchies, read method parameters, and everything else you need for code generation.
- ASM: For lower-level access, ASM has support for parsing source files (via its Tree API with source adapters) if you need more granular control.
Here's a quick workflow for this approach:
- Use
MavenProject.getCompileSourceRoots()to get all the project's Java source directories. - Iterate over every
.javafile in those directories. - Parse each file with JavaParser to extract the exact information you need for your code generation logic.
This is my go-to solution for most code-gen plugins—it avoids classloader headaches entirely and plays nicely with the GENERATE_SOURCES phase.
2. Dynamically Compile Sources to Memory & Load Them
If you must load actual class instances (e.g., for reflection, invoking static methods, or reading constant values), you can use the Java Compiler API to compile the project's sources in-memory, then load them into a custom ClassLoader.
Here's a rough breakdown of how to implement this:
- Pull the project's source roots and dependency classpath from
MavenProject(you already know how to handle dependencies, so focus on the sources). - Use
javax.tools.JavaCompilerwith a customJavaFileManagerto compile the source files into in-memory bytecode (no need to write anything to disk). - Create a custom ClassLoader that can load these in-memory classes, plus your existing dependency ClassLoader.
This approach gives you full access to loaded classes without polluting the project's official build output. The only catch is it adds a bit of complexity to your plugin code, but it's a robust solution for advanced use cases.
3. Pre-Compile to a Temporary Directory
Another straightforward option is to trigger a temporary compilation of the project's sources before your plugin runs—even in the GENERATE_SOURCES phase. You can do this by configuring the maven-compiler-plugin to run in an earlier phase (like initialize) and output to a separate temporary directory.
Here's how to set this up:
- In either your plugin's pom or the end-user project's pom, configure the
maven-compiler-pluginto execute in theinitializephase, with a custom output directory (e.g.,target/temp-classes). - In your plugin, create a ClassLoader that includes both this temporary directory and the project's dependencies.
- Add a cleanup step to the
cleanphase to delete the temporary directory so it doesn't clutter the build.
This is a simple fix if you want to reuse your existing ClassLoader logic without rewriting it—just make sure the temporary compilation doesn't interfere with the main build process.
Pro Tip: Leverage Maven's Built-in APIs
Maven has great built-in tools to simplify this work:
- Use
MavenProject.getCompileSourceRoots()to reliably get all source directories. - Use
DependencyResolutionUtilsto fetch the full classpath for dependencies. - These APIs ensure your plugin works with standard Maven project structures, so you don't have to reinvent the wheel.
内容的提问来源于stack exchange,提问作者Eira Rees

