Moving expensive code from runtime to compilation using ahead-of-time compilation? #4947
-
Hi, I want to execute "expensive" code at compile time and save the result so that it is available at runtime. It could be a simple string but maybe also an object. What is the best approach? For example I want to determine all xyz-files in the resources folder and have that constant list of file names available at runtime without scanning the resources. I got some hints here to use ahead of time compilation so I defined an annotation (ResourceScan) and implemented a visitor. This visitor does the calculation and calls annotate(...) However, this has some limitations
Any hints how to accomplish this in general? Or a specific solution to scan for all xyz files in the resources? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
So in general Micronaut's compile time facilities are for processing source code and generating files based on the definition of annotations in the source code via annotation processing. There are two modes for this, one is an isolating generator that generates a single source file for each annotated class. Say for example you want to generate some schema JSON file for each class annotated with public final class SchemaGeneratingTypeElementVisitor implements TypeElementVisitor<Entity, Object> {
private Map<ClassElement, Map> jsonPerClass = new LinkedHashMap();
@Override
public VisitorKind getVisitorKind() {
return VisitorKind.ISOLATING;
}
@Override
public void visitClass(ClassElement element, VisitorContext context) {
jsonPerClass.put(element, createSchemaJSON(element));
}
@Override
public void finish(VisitorContext visitorContext) {
jsonPerClass.forEach((classElement, json) -> {
visitorContext.visitMetaInfFile(classElement.getSimpleName() + ".json", classElement)
.ifPresent((generatedFile) -> {
try (Writer writer = generatedFile.openWriter()) {
objectMapper.writeJson(json, writer);
}
});
});
}
} This works well incrementally since each time you change an entity and can re-generate for just a single entity. The other supported approach is aggregating where a single registry type file is produced from lots of entities. Here is another example: public final class SchemaGeneratingTypeElementVisitor implements TypeElementVisitor<Entity, Object> {
private Map<String, Map> schema = new LinkedHashMap();
private Set<ClassElement> classElements = new HashSet();
@Override
public VisitorKind getVisitorKind() {
return VisitorKind.AGGREGATING;
}
@Override
public void visitClass(ClassElement element, VisitorContext context) {
schema.put(element.getName(), createSchemaJSON(element));
classElements.add(element);
}
@Override
public void finish(VisitorContext visitorContext) {
visitorContext.visitMetaInfFile("schema.json", classElements.toArray(new ClassElement[0]))
.ifPresent((generatedFile) -> {
try (Writer writer = generatedFile.openWriter()) {
objectMapper.writeJson(schema, writer);
}
});
}
} In this case every time any entity is changed it needs to re-run the whole visitor for all class elements. So those are the two approaches supported. What you are asking doesn't really fit either of those because there is no way for the compiler to say or know that for example the You can probably do it by generating a file with no originating elements, but it would break incremental compilation and mean EVERY change the user makes would need to re-compile everything which is maybe undesirable but could meet your requirements. Looking at the requirements it sounds like you would be better off using an external build tool level task to achieve what you want to do. |
Beta Was this translation helpful? Give feedback.
So in general Micronaut's compile time facilities are for processing source code and generating files based on the definition of annotations in the source code via annotation processing.
There are two modes for this, one is an isolating generator that generates a single source file for each annotated class. Say for example you want to generate some schema JSON file for each class annotated with
@Entity
you could do that by defining an isolatingTypeElementVisitor
that visits theEntity
annotation and generates a file for each class, here is some example pseudo code: