7

While looking for informations on stackoverflow, I have seen a question similar to mine, but with no real answer here.

I need migrating my maven project from guava 11.0.2 to guava 14 or higher (I need RangeSet). I updated my maven pom with the dependency:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>14.0</version>
</dependency>

I then run the maven build, and got this error:

[ERROR] xxx.java: cannot find symbol
[ERROR] symbol  : class Nonnull
[ERROR] location: package javax.annotation

I took a look closer, and this annotations is provided with JSR305, on which depends guava 11.0.2, as mvn repository reports it.

What I find strange is that guava 14 also depends on JSR305 as mvn repository reports.

If I add the JSR dependency to my pom, then the compilation just runs fine:

<dependency>
    <groupId>com.google.code.findbugs</groupId>
    <artifactId>jsr305</artifactId>
    <version>1.3.9</version>
    <scope>provided</scope>
</dependency>

But why would I have to add this dependency to my pom if guava already depends on it ? This looks more to a workaround than to a solution, and I would prefer to understand and make things clean.

Thanks for participating.

Community
  • 1
  • 1
Rémi Doolaeghe
  • 2,034
  • 3
  • 26
  • 45

1 Answers1

13

The reason that you need to add it as a dependency is because Guava 14 defines the dependency in their pom as follows:

<dependency>
    <groupId>com.google.code.findbugs</groupId>
    <artifactId>jsr305</artifactId>
    <version>1.3.9</version>
    <scope>provided</scope>
</dependency>

The important part for your problem is the <scope>provided</scope> line.

From the maven website they state the following with regards to provided dependencies:

provided: This is much like compile, but indicates you expect the JDK or a container to provide the dependency at runtime. For example, when building a web application for the Java Enterprise Edition, you would set the dependency on the Servlet API and related Java EE APIs to scope provided because the web container provides those classes. This scope is only available on the compilation and test classpath, and is not transitive.

So basically because Guava have set this as a provided dependency they expect whoever is consuming Guava to provide this dependency which is exactly what you have had to do.

In Guava 11.0.2 it was a normal compile dependency, hence you didn't have to provide it in your own project.

The change was made in Guava 13. From the release notes:

Made findbugs a provided dependency to avert dep conflicts when using findbugs 2.0. The side-effect of this change is that projects which relied upon Guava to grant access to the JSR-305 annotations "for free" will break unless they provide their own direct dependency on that jar (or an equivalent). Projects should always have been directly depending on JSR-305 (per maven best-practice), but this change makes that should into a must.

DB5
  • 12,346
  • 6
  • 59
  • 65
  • 2
    Yes and no. You can try this yourself - create a clean project only with Guava and without JSR-305. Everything will work fine in Java (at least in Java 7, not sure about Java 8). That's because you don't need the classes for annotations at run-time. See for example http://stackoverflow.com/questions/3567413/why-doesnt-a-missing-annotation-cause-a-classnotfoundexception-at-runtime. With Scala, though, this is a different song and you are right. – Petr Janeček Jun 17 '14 at 13:28
  • In my case, I need it at runtime, so DB5 answer fits to me. – Rémi Doolaeghe Jun 17 '14 at 14:31
  • 1
    Everything in Guava itself should work fine without the JSR-305 jar at runtime. If you were using JSR-305 annotations in your own code, then yeah, you need to depend on it directly now to compile. (You still shouldn't need it at runtime unless you're doing reflection on the annotations for some reason.) – ColinD Jun 17 '14 at 17:00
  • So I'm confused about this whole deal related to runtime retention. If I include Guava as a dependency in my application, yet I don't include `jsr305` as a dependency, if I use reflection on my code do I run the risk of an exception being thrown because a method indicates that it uses the `@Nonnull` annotation for example, yet `jsr305` was not included in the binary? – Garret Wilson Oct 07 '17 at 22:37