When compiling code that depends on Guava 21.0, [Edit: I mistakenly said 20.0 originally] using Maven, I get many warning messages like this:
Cannot find annotation method 'value()' in type 'com.google.errorprone.annotations.CompatibleWith': class file for com.google.errorprone.annotations.CompatibleWith not found
I do not use the errorprone library in my code, so this error message is due to its use by Guava.
Obviously, these are only warning messages and are not critical.
The reason is that we don't make the Error Prone annotations available to our users at compile time. We could maybe change that, but our understanding has been that it shouldn't be necessary. Do you know if you're using any Maven plugins that might be plugging into the compiler (annotation processors, mainly)?
These warnings are happening even in some pretty simple packages where there are no exotic maven plugins.
It does not happen on all of my modules that use Guava. But I haven't narrowed-down which Guava class is involved.
The warnings happen during the "default-compile" step from maven-compiler-plugin. I've tried version 3.3 and 3.6 of that plugin.
The warnings appear even if I set <showWarnings>false</showWarnings>
Ok. So this is related to annotation processors of some basic sort. My standard build involves this:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgs>
<arg>-Xlint:all</arg>
<arg>-Xlint:-serial</arg>
</compilerArgs>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
</plugins>
</build>
The warnings are shown only when I include Xlint along with either of showWarnings or showDeprecation.
Then 9 identical warnings appear if my java code contains one single line like this:
ImmutableTable.Builder<?,?,?> builder = ImmutableTable.builder();
So, I don't know if there is a bug in maven compiler plugin, or in Guava's ImmutableTable or what. But I really shouldn't be seeing these warnings.
Again, not a bug in the program operation, just an annoying set of warning messages.
We ran into this attempting to upgrade the jdbi3 project to Guava 21:
https://github.com/jdbi/jdbi/pull/697
We also don't do anything super fancy with Maven plugins, but we do attempt to set "warnings as errors" everywhere. That said, despite being logged at ERROR level, it doesn't fail the build.
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.5.1:
testCompile (default-testCompile) on project jdbi3-sqlobject: Compilation failure
[ERROR] /home/travis/.m2/repository/com/google/guava/guava/21.0/guava-21.0.jar(com/google/common/collect/Multimap.class):
warning: Cannot find annotation method 'value()' in type 'CompatibleWith':
class file for com.google.errorprone.annotations.CompatibleWith not found
Thanks. I tried pulling the jdbi3 and running mvn clean install. It successes without the CompatibleWith message. Is there a different command I should use or a different commit I should check out?
No, sorry, an earlier version of this comment incorrectly stated the build failed.
The actual problem is that the javac output all gets logged at the maximum error level -- so the WARNING that this emits will be represented as an ERROR if there are other build errors, which is confusing. Once you fix the other unrelated build errors this message then gets downgraded to a WARNING. So it does not actually break out build, but it does introduce warnings -- which as soon as "warnings as errors" gets fixed (someday :crossed_fingers:) it will then actually fail the build
I am also seeing this, on a standard javac -Xlint -Werror build with ant.
The messages are
[javac] .../guava.jar(com/google/common/collect/Multiset.class): warning: Cannot find annotation method 'value()' in type 'CompatibleWith': class file for com.google.errorprone.annotations.CompatibleWith not found
[javac] .../guava.jar(com/google/common/collect/Multiset.class): warning: Cannot find annotation method 'value()' in type 'CompatibleWith'
[javac] error: warnings found and -Werror specified
Because we want to use -Werror, this breaks our build and prevents us from upgrading Guava.
@PhilippWendler thanks for trying javac. Which JDK version is it?
I have found that I can eliminate the warning message in a Maven build by using this flag for the maven-compiler-plugin: <forceJavacCompilerUse>true</forceJavacCompilerUse>. That should make Maven use the javac command in my jdk, which is 1.8.0_66. I don't exactly understand why that removes the warning.
I tested with javac 1.8.0_111 from OpenJDK.
Running mvn clean install on jdbi3 didn't give me any output that mentions "CompatibleWith" anywhere. I tried with -Dmaven.compiler.forceJavacCompilerUse=true, and I tried introducing a compile error into a file that uses Multimap, and I still don't see it.
If anyone can point me to a repository and a command that I can use to reproduce this, that would be a big help. There's definitely something wrong, but I need to figure out where to point the finger (which might be at us -- I'm not just not sure yet).
In the meantime, as a workaround, you can probably add an explicit dependency on:
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<version>2.0.15</version>
^ And if you declare that dependency <scope>provided</scope>, then it shouldn't end up in your final aggregate build artifact (WAR, Uber JAR, etc.), meaning there should be no downside to doing so.
You should be able to reproduce the problem in branch guava21 of sosy-lab/java-common-lib. You can start a build with javac with ant clean build-project. The definition of the ant target that calls javac is in build/build-compile.xml, you can see the compiler options there.
The problem is reproducible with this branch on AppVeyor (log) and Travis (log).
Btw, we are even using error-prone already (though I disabled it in that branch for easier debugging) and want to upgrade to 2.0.15 at some point anyway, but I think that it would still be good if Guava would not have this problem.
The Eclipse Java Compiler builds our project just fine (ant clean build-project-ecj).
@cpovirk To reproduce the problem in Maven you must use both Xlint and showWarnings or showDeprecation. @PhilippWendler did something similar with javac -Xlint -Werror. So it may be that the problem is related to lint.
You can then reproduce it with a project containing one single java class like this:
java
public class GuavaTest {
private ImmutableTable.Builder table = ImmutableTable.builder();
}
@PhilippWendler , thanks, I'm now seeing the error. I'll poke around some more.
And thanks @enwired. I can reproduce with that, too.
We are also experiencing this issue. The noise makes it hard to want to push Guava 21 forward through all our projects.
As far as I can tell, this was our fault. Sorry about that. I've fixed it for 22.0. In the meantime, you can try the workaround above.
Any chance of a 21.1 release? Or is 22.0 coming soon?
Does the workaround work OK? Knowing that will help us prioritize.
@netdpb for an estimate on 22.0.
Does the workaround work OK?
Yes, it does work. However I don't think you should expect that everyone will go to github and search this issue.
To me personally this definitely seems like a defect large enough to warrant a patch release. It causes everyone who may treat warnings as errors to have to either search for this obscure issue, or to modify their projects in a way that is not reasonable (you should be able to reasonably treat warnings aggressively as external libraries should not be causing compiler warnings).
I'm using guava 22.0
I tried your workaround by adding
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<version>2.0.15</version>
I have a lot of warnings before and after applying the workaround like this
Compile with -strict or with -logLevel set to TRACE or DEBUG to see all errors.
Computing all possible rebind results for 'com.google.gwt.useragent.client.UserAgentAsserter'
Rebinding com.google.gwt.useragent.client.UserAgentAsserter
Checking rule <generate-with class='com.google.web.bindery.requestfactory.gwt.rebind.RequestFactoryGenerator'/>
[WARN] Unknown type 'com.google.web.bindery.requestfactory.shared.RequestFactory' specified in deferred binding rule
Checking rule <generate-with class='com.google.web.bindery.requestfactory.gwt.rebind.RequestFactoryEditorDriverGenerator'/>
[WARN] Unknown type 'com.google.web.bindery.requestfactory.gwt.client.RequestFactoryEditorDriver' specified in deferred binding rule
Checking rule <generate-with class='com.google.gwt.editor.rebind.SimpleBeanEditorDriverGenerator'/>
[WARN] Detected warnings related to 'com.google.gwt.editor.client.SimpleBeanEditorDriver'. Are validation-api-<version>.jar and validation-api-<version>-sources.jar on the classpath?
Specify -logLevel DEBUG to see all errors.
[WARN] Unknown type 'com.google.gwt.editor.client.SimpleBeanEditorDriver' specified in deferred binding rule
Rebinding com.google.gwt.useragent.client.UserAgentAsserter
Checking rule <generate-with class='com.google.web.bindery.requestfactory.gwt.rebind.RequestFactoryGenerator'/>
[WARN] Unknown type 'com.google.web.bindery.requestfactory.shared.RequestFactory' specified in deferred binding rule
Checking rule <generate-with class='com.google.web.bindery.requestfactory.gwt.rebind.RequestFactoryEditorDriverGenerator'/>
[WARN] Unknown type 'com.google.web.bindery.requestfactory.gwt.client.RequestFactoryEditorDriver' specified in deferred binding rule
Computing all possible rebind results for 'com.google.gwt.user.client.DocumentModeAsserter'
Rebinding com.google.gwt.user.client.DocumentModeAsserter
Checking rule <generate-with class='com.google.web.bindery.requestfactory.gwt.rebind.RequestFactoryGenerator'/>
[WARN] Unknown type 'com.google.web.bindery.requestfactory.shared.RequestFactory' specified in deferred binding rule
Checking rule <generate-with class='com.google.web.bindery.requestfactory.gwt.rebind.RequestFactoryEditorDriverGenerator'/>
[WARN] Unknown type 'com.google.web.bindery.requestfactory.gwt.client.RequestFactoryEditorDriver' specified in deferred binding rule
Rebinding com.google.gwt.user.client.DocumentModeAsserter
Checking rule <generate-with class='com.google.web.bindery.requestfactory.gwt.rebind.RequestFactoryGenerator'/>
[WARN] Unknown type 'com.google.web.bindery.requestfactory.shared.RequestFactory' specified in deferred binding rule
Checking rule <generate-with class='com.google.web.bindery.requestfactory.gwt.rebind.RequestFactoryEditorDriverGenerator'/>
[WARN] Unknown type 'com.google.web.bindery.requestfactory.gwt.client.RequestFactoryEditorDriver' specified in deferred binding rule
Computing all possible rebind results for 'com.google.gwt.logging.client.LogConfiguration
My guess is that those warnings are unrelated -- that they'd be there even if Guava weren't using these annotations at all. I don't know enough about GWT to say what the cause would be, though :(
The "Cannot find annotation method 'value()' in type 'CompatibleWith'" warning still appears with guava-22.0. Adding error_prone_annotations-2.0.19 to the dependencies helped.
Update on my comment: When compiling with guava-22.0 and jdk-1.8.0_31 the warning appears without the error_prone_annotations-2.0.19. With jdk-1.8.0_131 no errors, even without the error_prone_annotations jar.
I'm confess I don't yet everything that's going on here, and I'm afraid "just include the dependencies" may ignore some of the subtleties.
The first thing I don't understand is: what exactly is trying to call a method on an annotation that isn't included in the classpath? Secondly, how does that thing (whatever it is) _even know_ that the annotation has the value() method, if the annotation class is not on the classpath?
As was recently cleared up on one of my recent Stack Overflow questions (involving this same situation), it appears that if an annotation with a runtime retention policy is attempted to be accessed at runtime via reflection, yet that annotation is not present on the classpath, the JDK _should silently ignore the annotation_. (See also this related Stack Overflow answer.) So if missing annotations "just disappear" at runtime, how is this "thing" finding it and trying to call its valud() method --- or even knowing that it has a value() method?
Yes, I understand that the tricky part here is that the compiler isn't trying to access the class at runtime. But in a way that makes it even more mysterious how it even knows that the annotation has a value() method, if that annotation's class is not present at compile time. And why is this lint tool or whatever trying to call that method in the first place?
And lastly, does this even apply to the JSR 305 annotations? Do the JSR 305 methods even have any such methods that some tool would try to find at compile time? (Again, knowing the specifics of what tool was trying to access that method might make some of these answers more apparent.)
Plain javac is trying to look at the annotation. I don't think it's "calling" its method per se. I'm not sure _why_ it's looking at it. Apparently the class name and value are both present in the compiled class:
$ javap -v -cp guava-23.3-jre.jar com/google/common/collect/Multiset | grep -A 1 CompatibleWith
#24 = Utf8 Lcom/google/errorprone/annotations/CompatibleWith;
#25 = Utf8 value
I guess the idea is that the file needs to encode which specific annotation fields are set (and we do set the value of @CompatibleWith) to which specific values in case the code runs against a newer version of the annotation that has more fields available.
JSR 305 does have annotations with values, like @GuardedBy. I could imagine that they could cause the same problem, but I don't know whether it's happened in the wild.
Thanks, @cpovirk . This is really interesting. I wonder if javac is really doing the correct thing here. It doesn't seem be following the spirit of JLS 13.5.7, which says, "Adding or removing annotations has no effect on the correct linkage of the binary representations of programs in the Java programming language." (See the great answer to my question on Stack Overflow.)
I might have mentioned I'm probing this in depth, not to criticize Guava, but to determine the best thing to do in our own public Java library. I'm not sure that the best response is to say, "OK, we'll just force all users of our library to download several dependencies that they don't need to actually _use_ our library" just because of a somewhat obscure use case in which it's not even clear that javac is doing the right thing.
As you point out, @enwired could have worked around this problem simply by adding an explicit dependency to error_prone_annotations. Guava's "solution" is to basically force @enwired (and everybody else) to include this dependency --- along with several other dependencies, the absence of which were not causing _anybody_ problems that we know of.
So it's a really interesting situation from a technical standpoint. From a semantics standpoint, I haven't made a final decision but it still seems more appropriate to me (see further discussion in #1018) to make the JSR 305 dependency <optional> in our own library, and let the few people it affects (if anyone) explicitly include the JSR 305 dependency themselves.
Thanks for discussing this with me!
The error here apparently used to be fatal in all cases. The javac people changed it to be only a warning, and I guess they figured that was good enough. But of course that's still a problem for users of -Werror.
I found this bug: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6550655
That links to http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6365854, which says:
The rationale [for the warning] is that the missing annotation can cause problems when running the program.
And also:
The compiler cannot determine if the missing annotation has the meta-annotation
@Inherited. This can cause problems for annotation processors.
As the original submitter of this bug, I'll add my two cents.
I think that there is something fishy about the fact that javac reports compiler warnings about code that is not part of the code being compiled. I no longer think this is a bug of guava. The change made in the guava pom file seems like a work-around for a deficiency in javac or in java language specification related to annotations.
The details are above my level of understanding.
I wish there were some way to avoid forcing me to include a dependency on errorprone. This particular library doesn't bother me because it is small and useful. But the general principal that could lead to other libraries becoming forced inclusions in the future does bother me.
Perhaps javac could implement an additional 'SuppressWarnings' directive for this case. But I'm not going to file a request for that myself.
After pondering this discussion, for my own library (see https://globalmentor.atlassian.net/browse/JAVA-47) I've decided to go with <optional> after all. Even assuming that javac is doing the correct thing here (and I'm not convinced it is), @enwired (in the hypothetical case that he used our library) simply has a use case/configuration for which he actually needs one or more of dependencies to be present, so he can explicitly include it. In my view that is in fact precisely the semantics of <optional>: not everybody needs it, but those who need it, like @enwired , can include it explicitly.
Thanks again for all the info and help with the research.
FWIW, an alternative solution I found (at least on Oracle JDK 1.8.0_151) for nixing these warnings is available through javac flags (for Maven, these can be set in the maven-compiler-plugin config):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<!-- Suppress warnings for RUNTIME annotations used in dependencies
but missing from classpath -->
<arg>-Xlint:-processing</arg>
</compilerArgs>
</configuration>
</plugin>
It seems like the optional dependency is a much more surgical solution (the above will silence _all_ javac annotation processor warnings), but this option avoids pulling in an unused jar for compilation. I'm going the optional dep route in my library as well, but thought this might be of interest to others.
Thanks. To be clear, -Xlint:processing may work around problems with annotation processors, but it doesn't work around problems with plain javac with the warnings turned up:
$ javac -Xlint:all,-processing -Werror -cp $HOME/.m2/repository/com/google/guava/guava/23.0/guava-23.0.jar GuavaTest.java
/usr/local/google/home/cpovirk/.m2/repository/com/google/guava/guava/23.0/guava-23.0.jar(com/google/common/collect/Table.class): warning: Cannot find annotation method 'value()' in type 'CompatibleWith': class file for com.google.errorprone.annotations.CompatibleWith not found
/usr/local/google/home/cpovirk/.m2/repository/com/google/guava/guava/23.0/guava-23.0.jar(com/google/common/collect/Table.class): warning: Cannot find annotation method 'value()' in type 'CompatibleWith'
/usr/local/google/home/cpovirk/.m2/repository/com/google/guava/guava/23.0/guava-23.0.jar(com/google/common/collect/Table.class): warning: Cannot find annotation method 'value()' in type 'CompatibleWith'
/usr/local/google/home/cpovirk/.m2/repository/com/google/guava/guava/23.0/guava-23.0.jar(com/google/common/collect/Table.class): warning: Cannot find annotation method 'value()' in type 'CompatibleWith'
/usr/local/google/home/cpovirk/.m2/repository/com/google/guava/guava/23.0/guava-23.0.jar(com/google/common/collect/Table.class): warning: Cannot find annotation method 'value()' in type 'CompatibleWith'
/usr/local/google/home/cpovirk/.m2/repository/com/google/guava/guava/23.0/guava-23.0.jar(com/google/common/collect/Table.class): warning: Cannot find annotation method 'value()' in type 'CompatibleWith'
/usr/local/google/home/cpovirk/.m2/repository/com/google/guava/guava/23.0/guava-23.0.jar(com/google/common/collect/Table.class): warning: Cannot find annotation method 'value()' in type 'CompatibleWith'
/usr/local/google/home/cpovirk/.m2/repository/com/google/guava/guava/23.0/guava-23.0.jar(com/google/common/collect/Table.class): warning: Cannot find annotation method 'value()' in type 'CompatibleWith'
/usr/local/google/home/cpovirk/.m2/repository/com/google/guava/guava/23.0/guava-23.0.jar(com/google/common/collect/Table.class): warning: Cannot find annotation method 'value()' in type 'CompatibleWith'
error: warnings found and -Werror specified
1 error
9 warnings
It might still be a perfectly good solution for some people, since most people don't use -Xlint -Werror.
Most helpful comment
Yes, it does work. However I don't think you should expect that everyone will go to github and search this issue.
To me personally this definitely seems like a defect large enough to warrant a patch release. It causes everyone who may treat warnings as errors to have to either search for this obscure issue, or to modify their projects in a way that is not reasonable (you should be able to reasonably treat warnings aggressively as external libraries should not be causing compiler warnings).