In Project Annotation Proccessor

very short: Some classes are required by my annotation proccessor which when run first compiles the whole project to run which fails because of the classes that its generating missing in some other classes because they are loaded at the same time causing a chikcen egg problem. Running in different sub projects causes either a dependency loop or missing dependencies for some classes with dependencies. full explenation: I recently stumbled across annotation Proccessing and wrote one that works for my purposes as long as its in a different gradle project. However If I want to add something that utilises Classes from my main Code I need to change the location to that other class including that classes dependencies which is quite annoying. However I cant put it in the same project since parts of my code are generated using that annotation Proccessor. That means that the compilation which is needed before the processing fails since the imports to those auto generated classes fail since they are deleted on regeneration. meaning a chicken and egg problem. However the classes that use that generated code are not required by my processor. Meaning I basically would have to only compile the annotation processor first and then the classes as it needs them. After that the rest can be compiled. Question is how could I do that? any other way is also fine by me.
39 Replies
JavaBot
JavaBot2w ago
This post has been reserved for your question.
Hey @Hype_the_Time! Please use /close or the Close Post button above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically marked as dormant after 300 minutes of inactivity.
TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.
dan1st
dan1st2w ago
Split it into two modules you create one module containing the annotation processor and one module with the actual code using the annotation processor then the annotation processor doesn't run on itself
Hype_the_Time
Hype_the_TimeOP2w ago
problem is that i need some of the classes and i get a dependency loop if i implement import them in gradle. for some classes i can use a simple string refernce but for some i actually need to check the class. mainly to check whther a class extends a other one.
dan1st
dan1st2w ago
Just only put the annotation processor code in the annotation processor module and make sure nothing in there needs the annotation processor and that the annotation processor doesn't need the other module annotation processors should ideally not run application code
Hype_the_Time
Hype_the_TimeOP2w ago
my code doesnt run it but it uses it for some generation logic. mainly it checks for fields of the annotated class and whether they extend a specific class. there are some reasons for checking the class rn. not aware for a fix of that (without class being defined)
dan1st
dan1st2w ago
the annotation processor doesn't need to be dependent on these classes you can implement it without the class being present
Hype_the_Time
Hype_the_TimeOP2w ago
how?
dan1st
dan1st2w ago
Why would you need it for compiling the annotation processor? the annotation processor can just use javax.processing APIs for accessing all the information it needs about application classes
Hype_the_Time
Hype_the_TimeOP2w ago
i dont need it to compile the proccessor. i need it for logic that is generated by the proccessor
dan1st
dan1st2w ago
then what's the problem there? Do you want to process generated classes? You can do that it would just happen in a later round
Hype_the_Time
Hype_the_TimeOP2w ago
mainly was missing a way to access the classes. (right now) i was using com. squareup. javapoet and i got a type nullpointer due to it being unable to reference the class type due too it not being accessible for it. one sec i am changing it to be in a different project again and coppying the exact error
dan1st
dan1st2w ago
yeah I think you can only access generated classes in consecutive rounds
Hype_the_Time
Hype_the_TimeOP2w ago
how do consecutive rounds work?
dan1st
dan1st2w ago
javac performs multiple rounds of compilation. In each round, it calls process giving you information about what happened in the current round etc
Hype_the_Time
Hype_the_TimeOP2w ago
basically i need to wait until a certain level and skip till then?
dan1st
dan1st2w ago
What do you need JDA's Button import for? what are you waiting for? if one generated class depends on another, you need to make sure you are generating the required class in the same round or before What in there needs another class?
Hype_the_Time
Hype_the_TimeOP2w ago
i made a own button class and i generate some code based on it for conevniency. I was reworking it because my handler had like 2k lines. a bit long.
dan1st
dan1st2w ago
so what's the problem with generating code based on your button class? Does your custom button class need the annotation processor for anything?
Hype_the_Time
Hype_the_TimeOP2w ago
List<VariableElement> buttonOptions = typeElement.getEnclosedElements().stream()
.filter(e -> e.getKind() == ElementKind.FIELD)
.filter(e -> processingEnv.getTypeUtils()
.isAssignable(e.asType(), processingEnv.getElementUtils()
.getTypeElement("de.hype.bbsentials.server.discord.options.AbstractButtonOption")
.asType())) // Match subclasses of AbstractButtonOption<T>
.map(e -> (VariableElement) e)
.filter(e -> processingEnv.getTypeUtils()
.isAssignable(e.asType(), processingEnv.getElementUtils()
.getTypeElement("de.hype.bbsentials.server.discord.options.AbstractButtonOption")
.asType())) // Match subclasses of AbstractButtonOption<T>
.map(e -> (VariableElement) e)
.toList();
List<VariableElement> buttonOptions = typeElement.getEnclosedElements().stream()
.filter(e -> e.getKind() == ElementKind.FIELD)
.filter(e -> processingEnv.getTypeUtils()
.isAssignable(e.asType(), processingEnv.getElementUtils()
.getTypeElement("de.hype.bbsentials.server.discord.options.AbstractButtonOption")
.asType())) // Match subclasses of AbstractButtonOption<T>
.map(e -> (VariableElement) e)
.filter(e -> processingEnv.getTypeUtils()
.isAssignable(e.asType(), processingEnv.getElementUtils()
.getTypeElement("de.hype.bbsentials.server.discord.options.AbstractButtonOption")
.asType())) // Match subclasses of AbstractButtonOption<T>
.map(e -> (VariableElement) e)
.toList();
abstract button option assignable
dan1st
dan1st2w ago
Is that what's failing?
stechy1
stechy12w ago
Hi, if you have some code used in a production code and also in annotations processor, you can extract it to a separated module...
Hype_the_Time
Hype_the_TimeOP2w ago
not 100% sure since i dont have line of error in my stacktrace cause i am not able to debug it etc but i am pretty sure that it is this. happened after i added it. recursive dependencies (code in it requiring dependecy which then requires a different class....) gets pretty annoying but yes. daniels rounds seems very promising so far from what i cought up which is saying nothing tbh.
dan1st
dan1st2w ago
From the Javadoc:
To be robust when running in different tool implementations, an annotation processor should have the following properties: The result of processing a given input is not a function of the presence or absence of other inputs (orthogonality). Processing the same input produces the same output (consistency). Processing input A followed by processing input B is equivalent to processing B then A (commutativity) Processing an input does not rely on the presence of the output of other annotation processors (independence)
https://docs.oracle.com/en/java/javase/21/docs/api/java.compiler/javax/annotation/processing/Processor.html
Processor (Java SE 21 & JDK 21)
declaration: module: java.compiler, package: javax.annotation.processing, interface: Processor
dan1st
dan1st2w ago
When does it crash? Why can't you debug it? Does the annotation processor/compilation crash or does running the application crash? you might want to follow that since not doing so may be annoying/cause unexpected things to happen and if you need some things to be processed before others, you could also ensure that they are in different modules with the one that should be processed later being dependent on the one that should be processed earlier If you want to debug the annotation processor itself, that should be possible in Maven, you can just run mvnDebug instead of mvn and attach a debugger it probably works similar with Gradle
Hype_the_Time
Hype_the_TimeOP2w ago
i tried bootjar (due too spring) with debug in intelij but it never hit a breakpoiint even at the start of process etc
dan1st
dan1st2w ago
you need to attach a debugger to the compilation in Maven, you'd need to run mvnDebug
dan1st
dan1st2w ago
Stack Overflow
how do you debug java annotation processors using intellij?
How do you debug java annotation processors using intellij? Preferably using IDEA IntelliJ. I tried setting a breakpoint inside the processor and running but it did not break.
dan1st
dan1st2w ago
Stack Overflow
how do you debug java annotation processors using intellij?
How do you debug java annotation processors using intellij? Preferably using IDEA IntelliJ. I tried setting a breakpoint inside the processor and running but it did not break.
dan1st
dan1st2w ago
and also others
Hype_the_Time
Hype_the_TimeOP2w ago
got debugging to work. Cannot invoke "javax.lang.model.element.TypeElement.asType()" because the return value of "javax.lang.model.util.Elements.getTypeElement(java.lang.CharSequence)" is null
List<VariableElement> buttonOptions = typeElement.getEnclosedElements().stream()
.filter(e -> e.getKind() == ElementKind.FIELD)
.filter(e -> processingEnv.getTypeUtils()
.isAssignable(e.asType(), processingEnv.getElementUtils()
.getTypeElement("de.hype.bbsentials.server.discord.options.AbstractButtonOption")
.asType())) // Match subclasses of AbstractButtonOption<T>
.map(e -> (VariableElement) e)
.filter(e -> processingEnv.getTypeUtils()
.isAssignable(e.asType(), processingEnv.getElementUtils()
.getTypeElement("de.hype.bbsentials.server.discord.options.AbstractButtonOption")
.asType())) // Match subclasses of AbstractButtonOption<T>
- .toList();
List<VariableElement> buttonOptions = typeElement.getEnclosedElements().stream()
.filter(e -> e.getKind() == ElementKind.FIELD)
.filter(e -> processingEnv.getTypeUtils()
.isAssignable(e.asType(), processingEnv.getElementUtils()
.getTypeElement("de.hype.bbsentials.server.discord.options.AbstractButtonOption")
.asType())) // Match subclasses of AbstractButtonOption<T>
.map(e -> (VariableElement) e)
.filter(e -> processingEnv.getTypeUtils()
.isAssignable(e.asType(), processingEnv.getElementUtils()
.getTypeElement("de.hype.bbsentials.server.discord.options.AbstractButtonOption")
.asType())) // Match subclasses of AbstractButtonOption<T>
- .toList();
fails when i continue after toList()
dan1st
dan1st2w ago
seems like de.hype.bbsentials.server.discord.options.AbstractButtonOption is not available Is that class generated?
Hype_the_Time
Hype_the_TimeOP2w ago
hm package seemed to be wrong probably happened during a refecactor
dan1st
dan1st2w ago
well that explains it lol
Hype_the_Time
Hype_the_TimeOP2w ago
while compilation didnt work again i expect these errors that i see right now. those are from other places which i still need to fix. some due too outcommented stuff. maybe there is one hiding some where in those error but for now seems to be done tyvm @dan1st | Daniel
dan1st
dan1st2w ago
ok if you have more questions about annotation processors, you can continue asking here or create a new post and ping me (you can ping me for other annotation processing related questions, please not necessarily for other questions)
Hype_the_Time
Hype_the_TimeOP2w ago
yeah was ware. i would close it but i want to keep it open until ik its done. if i remeber by then ill close it
dan1st
dan1st2w ago
if you don't, it isn't much of an issue
Hype_the_Time
Hype_the_TimeOP2w ago
very much aware
JavaBot
JavaBot2w ago
💤 Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.
Want results from more Discord servers?
Add your server