NoSuchMethodError: com.google.common.base.Stopwatc

2020-02-13 17:43发布

问题:

My app is throwing NoSuchMethodError: com.google.common.base.Stopwatch.createStarted()Lcom/google/common/base/Stopwatch error. Not sure why, because 16.0.1 do contain that class, I've checked. From what I have researched, it looks like this is a bug?

I also have this code for refernence, though I think this is not the issue:

    FirewallRule rule = new PeriodicFirewallCounterRule(60, TimeUnit.SECONDS, new IpAddressCountingPolicy());
    ((PeriodicFirewallCounterRule)rule).addHandler(new RateLimitationHandler(new UniqueLimitPolicy(10)));
    FirewallFilter firewallFiler = new FirewallFilter(getContext(), list(rule));
    firewallFiler.setNext(ma);

My app is using Restlet APISpark:

  <dependency>
      <groupId>org.restlet.gae</groupId>
      <artifactId>org.restlet.ext.apispark</artifactId>
      <version>${version.restlet}</version>
  </dependency>

When running and accessing the REST api of the app, it throws this error:

[INFO] Caused by: java.lang.NoSuchMethodError: com.google.common.base.Stopwatch.createStarted()Lcom/google/common/base/Stopwatch;
[INFO]  at org.restlet.ext.apispark.internal.firewall.rule.counter.PeriodicCounter.<init>(PeriodicCounter.java:65)
[INFO]  at org.restlet.ext.apispark.internal.firewall.rule.PeriodicFirewallCounterRule$1.load(PeriodicFirewallCounterRule.java:86)
[INFO]  at org.restlet.ext.apispark.internal.firewall.rule.PeriodicFirewallCounterRule$1.load(PeriodicFirewallCounterRule.java:84)
[INFO]  at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3599)
[INFO]  at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2379)
[INFO]  at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2342)
[INFO]  at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2257)
[INFO]  ... 74 more

回答1:

When using the extension org.restlet.ext.apispark, the guava dependency retrieved has the version 16.0.1.

Downloading: http://maven.restlet.com/com/google/guava/guava/16.0.1/guava-16.0.1.jar
Downloading: http://repo.maven.apache.org/maven2/com/google/guava/guava/16.0.1/guava-16.0.1.jar
Downloaded: http://repo.maven.apache.org/maven2/com/google/guava/guava/16.0.1/guava-16.0.1.jar (2176 KB at 711.7 KB/sec)

It comes within an application created from scratch with the following maven configuration:

<project (...)>
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.restlet</groupId>
    <artifactId>restlet-apispark-firewall</artifactId>
    <name>${project.artifactId}</name>
    <packaging>jar</packaging>
    <version>1.0.0-snapshot</version>

    <properties>
        <java-version>1.7</java-version>
        <restlet-version>2.3.1</restlet-version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.restlet.jse</groupId>
            <artifactId>org.restlet</artifactId>
            <version>${restlet-version}</version>
        </dependency>

        <dependency>
            <groupId>org.restlet.jse</groupId>
            <artifactId>org.restlet.ext.apispark</artifactId>
            <version>${restlet-version}</version>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>maven-restlet</id>
            <name>Public online Restlet repository</name>
            <url>http://maven.restlet.com</url>
        </repository>
    </repositories>
</project>

I integrated your code and it works fine on my side. No exception is thrown...

I think that an older version of Guava comes from another dependency. If you use Maven, you should identify where this old guava version comes from and perhaps add an exclude within the corresponding dependency. I hope that it will fix your problem...

Hope that helps you, Thierry



回答2:

This is the solution that fixed the error:

First exclude old Guava dependency then:

  <dependency>
      <groupId>org.restlet.gae</groupId>
      <artifactId>org.restlet.ext.apispark</artifactId>
      <version>${version.restlet}</version>
      <exclusions>
          <exclusion>
              <groupId>com.fasterxml.jackson.core</groupId>
              <artifactId>jackson-databind</artifactId>
          </exclusion>
      </exclusions>
  </dependency>
  <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.5.1</version>
  </dependency>


回答3:

The class Stopwatch loaded by that ClassLoader does not contain that method, not sure if caused by multiple incompatible jars as Jens says or simply because 16.0.1 does not really have that method. A simple check will be to parse the class with javap or a decompiler:

javap -p Stopwatch.class

And then check if that method is listed.

Edit: That method is there since 15.0, so i'd check the content of you classpath too.



回答4:

Referring to NoSuchMethodError Oracle Documentation :

The NoSuchMethodError: is thrown if an application tries to call a specified method of a class (either static or instance), and that class no longer has a definition of that method.

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.

I think you got this Exception because you have more than one version of this jar in your classpath, and since the createStarted() method is available from the 15.0 version I whould say that you have an other old version of it, probably due to a dependency problem.



回答5:

Moving to the latest version of Guava did it for me



回答6:

In my case one of my Maven dependencies was picking up a newer version of Guava (16.0.1) that apparently does not have this method. When I added an exclusion to that dependency in my pom.xml, instead an older (correct) version of Guava was picked up by another of my dependencies and then it worked.

You can find this by printing your dependency tree via mvn dependency:tree and then looking at what is picking up the newer version of guava. You might need to add more than one exclusion to get it right.