Java annotation processing intellij need to compile twice - java

I'm developping an annotation processor to generate some code but I'm having some compilation issues.
I'd like to be able to use the generated classes in the same module where the annotated interface that triggers the generation is located.
This does not work on the first compilation after deleting all generated sources though, although I thought that annotation processing should be run before compiling other sources.
So the references to the generated sources generate an error on the first run, stating the generated packages do not exist.
On a second run everything compiles fine, but I suspect the generated sources from the previous run are used, not the newly generated ones.
Am I perhaps missing some mechanism to configure this? Or is this expected behaviour?

The issue and it's solution are described here: https://code.google.com/p/acris/wiki/CodeGenerationPlatform_Pitfall_Rounds
The key is to wrap the code generation with
if (!roundEnv.processingOver()) { ... }
to avoid changing the generated files in the last compiler round.

Related

Unable to use AbstractProcessor in IDEs

Motivation:
In our code we have a few places where some methods are run by their name. There are some big if-else-if blocks with each function name and call of the corresponding method (I use the term function to describe just names, for example function X01 might correspond to method SomeClass.functionX01). I've been looking into ways to improve that
Goal:
Write just methods that are annotated with some custom annotation, removing the need to update or even include if-else-if blocks in order to run specific function. Have access to any generated code if any code is generated.
What I did:
I've created first prove of concept using runtime annotations and it proved successful, but slower then if-else-if. Next attempt was with source annotation
I've followed this link for an example, however it did not seam to run in IntelliJ. What I wanted is to have - in this case PersonBuilder class generated, instead there was none. In some cases an error was raised Error:java: Bad service configuration file, or exception thrown while constructing Processor object: javax.annotation.processing.Processor: Provider BuilderProcessor not found
After some Googling and failing to find anything I've turned to book (Core Java, Volume II - Advanced Features - 9th Edition, Polish translation) and there was reccomended to run the following commands:
javac [AbstractProcessor implementation]
javac -processor [Compiled Processor] [other source files to compile]
This worked, however is unsatisfactory as it needs to happen inside IDE (NetBeans and IntelliJ to be specific) automatically during build. Code does not need to be generated on the fly, but programmer must have access to it after build (as in - be able to call methods of generated classes)
Question:
How to have and use generated code used in NetBeans and IntelliJ without the need of using external tools? Is it possible, or using reflection, runtime annotations or external tools is the only way?
Additional info (just in case):
Language level: Java 1.8
JVM versions: 12 and 13
IDEs: NetBeans and IntelliJ

warning: No processor claimed any of these annotations: javax.annotation.Generated

I'm working on a module project in NetBeans 8.2, with a GUI and everything. I'm using lots of the IDE functionality to auto-generate code for the GUI.
Every time I do a clean build of my project, I get a warning from the compiler:
warning: No processor claimed any of these annotations:javax.annotation.Generated
Browsing the build directory, I see that the IDE generates a class for me, Bundle.java, and it slaps the given annotation on top of it:
#javax.annotation.Generated(value="org.netbeans.modules.openide.util.NbBundleProcessor")
I need this warning to go away. I tried searching the web for an annotation processor that processes this specific annotation but I had no luck. Does an annotation processor for this specific annotation exist?
If this is a "harmless warning," I need to understand why it is harmless to justify its existence in my build output.
If needed I can include in this question the argument to the -processorpath option that is passed to javac from the IDE; I didn't include it on purpose because it is very long but I can add it if necessary
EDIT #1:
I did a "hacky" modification to the common.xml file under the NetBeans installation directory to make the invocation to javac not include the -processorpath option, and doing so makes the warning dissapear. I still do not understand why that is the case
A simple fix for this is to remove the #Messages annotation from the TopComponent class that is generated by the NetBeans code generator. It is that annotation that is responsible for generating the Bundle class, as per the NbBundle.Messages API Documentation.
As soon as you remove that annotation, you might get warnings from other annotations that rely on the contents of the #Messages annotation (i.e. TopComponent.OpenActionRegistration), so make sure to modify the contents of those annotation as well until nothing in your code depends on that Bundle anymore.
Hopefully nothing else in your code relies on your Bundle.

Netbeans error Annotation processor 'org.checkerframework.checker.nullness.NullnessChecker' not found

I'm trying to get NonNull annotations working in NetBeans, and it's been one headache after another.
I followed the instructions at https://checkerframework.org/manual/#netbeans and can confirm that checker-qual.jar is added as both a compile and processor library. I've enabled annotation processing and added org.checkerframework.checker.nullness.NullnessChecker as an Annotation Processor.
In the source code I can import import org.checkerframework.checker.nullness.qual.NonNull and have #NonNull annotations compile. However while building I get this:
error: Annotation processor 'org.checkerframework.checker.nullness.NullnessChecker' not found
What do I need to do to resolve this error?
The instructions for the NetBeans processor path are incorrect: they first talk about adding checker.jar, but then mention checker-qual.jar https://github.com/typetools/checker-framework/blob/master/docs/manual/external-tools.tex#L904
checker.jar contains the actual annotation processor and should be put on the processor path.
I'll update the instructions.
However, we did not yet find a way to add the annotated JDK jdk8.jar to the bootclasspath that the processor uses. Therefore, none of the JDK annotations that are provided will be visible within NetBeans. We will therefore need to remove support for the Nullness Checker from NetBeans, until we find a proper solution.

How do I make error-prone ignore my generated source code?

I've recently discovered Error Prone and am integrating it into my Android build using the Gradle plugin linked on their page.
Since our project is using Icepick (and some other code generating annotation processors), we have generated source code, which gets compiled in. Unfortunately, some of the generated code triggers warnings in Error Prone, and I'd like to filter that noise out somehow.
The generated code shows up in the app/build/generated/source/apt/debug directory. How can I exempt this code from Error Prone's steely gaze?
Use the flag -XepDisableWarningsInGeneratedCode
See this issue on GitHub
In my case classes were annotated with #AvroGenerated and -XepDisableWarningsInGeneratedCode didn't work.
The solution was to exclude build directory from checks via -XepExcludedPaths:.*/build/.*

Java "NoSuchMethodError"

I'm getting:
NoSuchMethodError: com.foo.SomeService.doSmth()Z
Am I understanding correctly that this 'Z' means that return type of doSmth() method is boolean? If true, then that kind of method really does not exist because this method returns some Collection. But on the other hand if I call this method, I'm not assigning its return value to any variable. I just call this method like this:
service.doSmth();
Any ideas why this error occurs? All necessary JAR files exist and all other methods from this class seems to exist.
Looks like method exists in classpath during compilation, but not during running of your application.
I don't think return type is a problem. If it was, it wouldn't compile. Compiler throws error when method call is ambiguous, and it is when two methods differ only by return type.
Normally, this error is caught by the compiler; this error can only occur at run time if the definition of a class has incompatibly changed.
In short - a class/jar file at runtime is not the same that you used at compile time.
This is probably a difference between your compile-time classpath and you run-time classpath.
Here is what seems to be going on:
The code is compiled with a class path that defines the doSmth() method returning a boolean. The byte-code refers to the doSmth()Z method.
At runtime, the doSmth()Z method isn't found. A method returning a Collection is found instead.
To correct this problem, check your (compile time) classpath.
The current reply just tell you why is failing. Usually is even nicer to know how to fix problems. As it is mentioned, the problem usually is that you built your program but when running or exporting it, the library is not included. So the solution is...
If you are running, check the the run configuration
Select Run tab -> Run configurations -> Select the configuration you are running -> Check the Classpath tab -> Ensure the libraries you need are there
If you are exporting (for example a war file), follow this
Select project -> Select properties -> Select Deployment Assembly -> Press Add -> Select Java Build Path Entries -> Select the libraries you want to be included in your exported file (for example a war file)
In both cases, ensure the library which you are referencing in included.
Other frequent problems for this error are not the right type of parameters or visibility but then, the compiler will detect the error before running. In this case, just check the documentation to match the function and package visibility, and ensure that the library is found in Java Build Path in your project properties.
Maybe still can help somebody, but this exception can happen also when you have on the classpath two classes in different jar files that have the same exact signature but they haven't the same public methods.
For example:
On file mylibrary1.jar you have class com.mypackage.mysubpackage.MyClass with method doSmth()
On file mylibrary2.jar you have class com.mypackage.mysubpackage.MyClass without method doSmth()
When searching the class, the classloader may find first mylibrary2.jar depending on the path precedence but can't find the method on that class.
Be sure you don't have the same package + class on two different files.
I noticed this problem occurring while testing some experimental changes in multiple linked projects, after updating them from SVN in Eclipse.
Specifically, I updated all projects from SVN, and reverted the .classpath file rather than edit it manually to keep things simple.
Then I re-added the linked projects to the path, but forgot to remove the related jars. This was how the problem occurred for me.
So apparently the run time used the jar file while the compiler used the project files.
Another way this can happen and is difficult to find:
If a signature of a method in an external jar changes in a way that there is no error found in the IDE because it's still compatible with how you call it the class might not be re-compiled.
If your build checks the files for changes and only then recompiles them, the class might not be recompiled during the build process.
So when you run it this might lead to that problem. Although you have the new jar, your own code expects still the old one but does never complain.
To make it harder it depends on the jvm if it can handle such cases. So in the worst case it runs on the test server but not on the live machine.

Categories

Resources