General question
I have two projects A and B; B has a dependency on A. I want to generate some code in B with an Annotation Processor, based on annotations on objects in A. When I run the compilation with the correct Processor implementation, only the annotated objects from B are picked up.
I understand that scanning other JARs must be disabled by default, because you usually don't want to do an annotation scan for all your dependencies. I also understand that it may be impossible to do what I want to do because of compiler magic - which I don't know a lot about - but I'm hoping it's not.
Specific case
My projects are called DB and WEB. WEB obviously depends on DB for its JPA access; this is configured in Maven. Due to a number of architectural choices, DB must remain a separate JAR. DB doesn't use Spring except for some annotations which are consumed by WEB; WEB uses Spring MVC.
I'm trying to generate the CrudRepository
interfaces for all my JPA entities with an Annotation Processor. The @Repository
objects are supposed to go in a repo
package in the WEB project, so they can be used with @Autowired
wherever in my WEB application. The annotation I'm performing the scan for is @javax.persistence.Entity
, but I've also tried a custom annotation, with the same results.
@SupportedAnnotationTypes("javax.persistence.Entity")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class RepositoryFactory extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element e : roundEnv.getElementsAnnotatedWith(Entity.class)) {
if (e.getKind() != ElementKind.CLASS) {
continue;
}
// TODO: implement logic to skip manually implemented Repos
try {
String name = e.getSimpleName().toString();
TypeElement clazz = (TypeElement) e;
JavaFileObject f = processingEnv.getFiler().
createSourceFile("blagae.web.repo." + name + "Repo");
try (Writer w = f.openWriter()) {
PrintWriter pw = new PrintWriter(w);
pw.println("package blagae.web.repo;");
pw.println("import org.springframework.data.repository.CrudRepository;");
pw.printf("import %s;\n", clazz.toString());
pw.println("import org.springframework.stereotype.Repository;");
pw.println("@Repository");
pw.printf("public interface %sRepo extends CrudRepository<%s, Long> {}\n", name, name);
pw.flush();
}
} catch (IOException ex) {
Logger.getLogger(RepositoryFactory.class.getName()).log(Level.SEVERE, null, ex);
}
}
return false;
}
}
Ideally, I'd love for someone to tell me about an annotation that would be as simple as
@ComponentScan(basePackages = "blagae.db.*")
But of course, I'm not counting on that because it would probably be documented somewhere. As a workaround, I could just add the Spring dependency to the db and generate the classes there, but they only serve a purpose in the Spring MVC app. I'm also wary of the config it might take to make this work.
UPDATE
Some extra info: I'm using the maven-processor-plugin, which I've verified to work well in the WEB project for classes that are defined there. However, I specifically want access classes annotated in the dependency project DB. I have looked into the method AbstractProcessor::getSupportedOptions
but it's unclear to me what I could do there.
Maven config:
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>2.2.4</version>
<configuration>
<processors>
<processor>blagae.utils.RepositoryFactory</processor>
</processors>
</configuration>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
</execution>
</executions>
</plugin>
SUGGESTION
Another random thought I had would be to run a JavaCompiler
process for the DB project in WEB, but how would I inject my Processor
?