doanduyhai / Achilles

An advanced Java Object Mapper/Query DSL generator for Cassandra
http://achilles.archinnov.info
Apache License 2.0
241 stars 92 forks source link

Achilles Junit: NoClassDefFoundError: com/codahale/metrics/JmxReporter #353

Closed SergiusSidorov closed 5 years ago

SergiusSidorov commented 5 years ago

Spring Boot 2.1, Cassandra driver 3.6.0, achilles-junit 6.0.0

I use achilles-junit as embedded Cassandra in spring boot test cases. But after upgrade from Spring boot 2.0 to 2.1 the tests fail with an exception:

java.lang.NoClassDefFoundError: com/codahale/metrics/JmxReporter
    at com.datastax.driver.core.Metrics.<init>(Metrics.java:146)
    at com.datastax.driver.core.Cluster$Manager.init(Cluster.java:1501)
    at com.datastax.driver.core.Cluster.init(Cluster.java:208)
    at com.datastax.driver.core.Cluster.connectAsync(Cluster.java:376)
    at com.datastax.driver.core.Cluster.connectAsync(Cluster.java:355)
    at com.datastax.driver.core.Cluster.connect(Cluster.java:305)
    at info.archinnov.achilles.embedded.AchillesInitializer.initializeFromParameters(AchillesInitializer.java:62)
    at info.archinnov.achilles.embedded.CassandraEmbeddedServer.<init>(CassandraEmbeddedServer.java:64)
    at info.archinnov.achilles.embedded.CassandraEmbeddedServerBuilder.buildServer(CassandraEmbeddedServerBuilder.java:535)
    at info.archinnov.achilles.junit.AchillesTestResource.buildServer(AchillesTestResource.java:141)
    at info.archinnov.achilles.junit.AchillesTestResource.<init>(AchillesTestResource.java:118)
    at info.archinnov.achilles.junit.AchillesTestResourceBuilder.build(AchillesTestResourceBuilder.java:216)
    at com.platincoin.gidra.oauth.server.CassandraEmbeddedIntegrationTest.embeddedCassandra(CassandraEmbeddedIntegrationTest.java:86)
    at com.platincoin.gidra.oauth.server.CassandraEmbeddedIntegrationTest.<init>(CassandraEmbeddedIntegrationTest.java:46)
    at com.platincoin.gidra.oauth.server.OAtuh2TokenReceivingTest.<init>(OAtuh2TokenReceivingTest.java:20)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:217)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:226)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)

The application starts without any errors. Library metrics-core is exist in classpath (v.4.0.3).

doanduyhai commented 5 years ago

mvn dependentry:tree to see which version of metrics-core is used and if there is a conflict, exclude it in your pom.xml

SergiusSidorov commented 5 years ago
[INFO] +- org.springframework.boot:spring-boot-starter-data-cassandra:jar:2.1.0.RELEASE:compile
[INFO] |  +- org.springframework:spring-tx:jar:5.1.2.RELEASE:compile
[INFO] |  \- org.springframework.data:spring-data-cassandra:jar:2.1.2.RELEASE:compile
[INFO] |     +- org.springframework.data:spring-data-commons:jar:2.1.2.RELEASE:compile
[INFO] |     \- com.datastax.cassandra:cassandra-driver-core:jar:3.6.0:compile
[INFO] |        +- io.netty:netty-handler:jar:4.1.29.Final:compile
[INFO] |        |  +- io.netty:netty-buffer:jar:4.1.29.Final:compile
[INFO] |        |  |  \- io.netty:netty-common:jar:4.1.29.Final:compile
[INFO] |        |  +- io.netty:netty-transport:jar:4.1.29.Final:compile
[INFO] |        |  |  \- io.netty:netty-resolver:jar:4.1.29.Final:compile
[INFO] |        |  \- io.netty:netty-codec:jar:4.1.29.Final:compile
[INFO] |        +- com.google.guava:guava:jar:19.0:compile
[INFO] |        +- io.dropwizard.metrics:metrics-core:jar:4.0.3:compile
[INFO] |        +- com.github.jnr:jnr-ffi:jar:2.1.7:compile
[INFO] |        |  +- com.github.jnr:jffi:jar:1.2.16:compile
[INFO] |        |  +- com.github.jnr:jffi:jar:native:1.2.16:runtime
[INFO] |        |  +- org.ow2.asm:asm-commons:jar:5.0.3:compile
[INFO] |        |  +- org.ow2.asm:asm-analysis:jar:5.0.3:compile
[INFO] |        |  +- org.ow2.asm:asm-tree:jar:5.0.3:compile
[INFO] |        |  +- org.ow2.asm:asm-util:jar:5.0.3:compile
[INFO] |        |  \- com.github.jnr:jnr-x86asm:jar:1.0.2:compile
[INFO] |        \- com.github.jnr:jnr-posix:jar:3.0.44:compile
[INFO] |           \- com.github.jnr:jnr-constants:jar:0.9.9:compile

io.dropwizard.metrics:metrics-core:jar:4.0.3:compile

doanduyhai commented 5 years ago

java.lang.NoClassDefFoundError: com/codahale/metrics/JmxReporter --> com.codahale.metrics is not found... You mvn dependency:tree only shows io.dropwizard.metrics, it's not the same thing ...

SergiusSidorov commented 5 years ago

io.dropwizard.metrics:metrics-core:jar v.3.2.6 has class com.codahale.metrics.JmxReporter. But in version 4.0.3 this class is absent. In version 4.x this class was moved to separate library (metrics-jmx). Current full name of the class is com.codahale.metrics.jmx.JmxReporter. Is it planned to support version 4.x in the new version of achilles-junit?

doanduyhai commented 5 years ago

It's weird, you're using com.datastax.cassandra:cassandra-driver-core:jar:3.6.0 but according to its pom.xml, they're pulling metrics version 3.2.2 and not 4.0.3, where does it come from ? Did you override java driver core dependencies in your pom.xml ?

https://github.com/datastax/java-driver/blob/3.6.0/pom.xml#L56

timtebeek commented 5 years ago

hi! came across this issue; found it when I switched to Spring Boot 2.1, which dependency manages cassandra-driver-core:3.6.0, which comes with metrics-core:4.0.5. Can anything be done for achilles-junit to support this setup with the new metrics-jmx, or make it an optional dependency? Right now this is blocking our test migration.

doanduyhai commented 5 years ago

@timtebeek will it solve your issue if I upgrade Achilles to use cassandra-driver-core:3.6.0 instead of cassandra-driver-core:3.6.0 ?

timtebeek commented 5 years ago

Yes! the code changes need to use cassandra-driver-core:3.6.0 will likely introduce dropwizard metrics 4.x into your code base as well, for which you might need the metrics-jmx dependency. It's either that more make the JMXExporter optional, as we don't need it when JUnit testing.

timtebeek commented 5 years ago

You seem to already disable JMX; https://github.com/doanduyhai/Achilles/blob/master/achilles-embedded/src/main/java/info/archinnov/achilles/embedded/AchillesInitializer.java#L120 It's just that it can't even find the class then I recon with metrics-core 4.x on the classpath.

doanduyhai commented 5 years ago

I just upgraded to cassandra-driver-core:3.6.0 and did a mvn dependency:tree, here is the result:

mvn dependency:tree | grep -B 10 "metrics-core"                                                                                                                                                                             ⭠ (master|✚1)
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ achilles-model ---
[INFO] info.archinnov:achilles-model:jar:6.0.1-SNAPSHOT
[INFO] +- com.datastax.cassandra:cassandra-driver-core:jar:3.6.0:compile
[INFO] |  +- io.netty:netty-handler:jar:4.0.56.Final:compile
[INFO] |  |  +- io.netty:netty-buffer:jar:4.0.56.Final:compile
[INFO] |  |  |  \- io.netty:netty-common:jar:4.0.56.Final:compile
[INFO] |  |  +- io.netty:netty-transport:jar:4.0.56.Final:compile
[INFO] |  |  \- io.netty:netty-codec:jar:4.0.56.Final:compile
[INFO] |  +- io.dropwizard.metrics:metrics-core:jar:3.2.2:compile
--
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ achilles-common ---
[INFO] info.archinnov:achilles-common:jar:6.0.1-SNAPSHOT
[INFO] +- info.archinnov:achilles-model:jar:6.0.1-SNAPSHOT:compile
[INFO] |  +- com.datastax.cassandra:cassandra-driver-core:jar:3.6.0:compile
[INFO] |  |  +- io.netty:netty-handler:jar:4.0.56.Final:compile
[INFO] |  |  |  +- io.netty:netty-buffer:jar:4.0.56.Final:compile
[INFO] |  |  |  |  \- io.netty:netty-common:jar:4.0.56.Final:compile
[INFO] |  |  |  +- io.netty:netty-transport:jar:4.0.56.Final:compile
[INFO] |  |  |  \- io.netty:netty-codec:jar:4.0.56.Final:compile
[INFO] |  |  +- io.dropwizard.metrics:metrics-core:jar:3.2.2:compile
--
[INFO] |  +- info.archinnov:achilles-model:jar:6.0.1-SNAPSHOT:compile
[INFO] |  \- com.google.guava:guava:jar:18.0:compile
[INFO] +- org.apache.commons:commons-lang3:jar:3.3.2:compile
[INFO] +- com.datastax.cassandra:cassandra-driver-extras:jar:3.6.0:compile
[INFO] |  \- com.datastax.cassandra:cassandra-driver-core:jar:3.6.0:compile
[INFO] |     +- io.netty:netty-handler:jar:4.0.56.Final:compile
[INFO] |     |  +- io.netty:netty-buffer:jar:4.0.56.Final:compile
[INFO] |     |  |  \- io.netty:netty-common:jar:4.0.56.Final:compile
[INFO] |     |  +- io.netty:netty-transport:jar:4.0.56.Final:compile
[INFO] |     |  \- io.netty:netty-codec:jar:4.0.56.Final:compile
[INFO] |     +- io.dropwizard.metrics:metrics-core:jar:3.2.2:compile
--
[INFO] |  +- org.antlr:antlr:jar:3.5.2:compile
[INFO] |  |  \- org.antlr:ST4:jar:4.0.8:compile
[INFO] |  +- org.antlr:antlr-runtime:jar:3.5.2:compile
[INFO] |  +- org.slf4j:jcl-over-slf4j:jar:1.7.7:compile
[INFO] |  +- org.codehaus.jackson:jackson-core-asl:jar:1.9.2:compile
[INFO] |  +- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.2:compile
[INFO] |  +- com.googlecode.json-simple:json-simple:jar:1.1:compile
[INFO] |  +- com.boundary:high-scale-lib:jar:1.0.6:compile
[INFO] |  +- org.yaml:snakeyaml:jar:1.11:compile
[INFO] |  +- org.mindrot:jbcrypt:jar:0.3m:compile
[INFO] |  +- io.dropwizard.metrics:metrics-core:jar:3.1.0:compile

As you can see, the most recent version of io.dropwizard.metrics:metrics-core is 3.2.2

doanduyhai commented 5 years ago

@timtebeek

You said I switched to Spring Boot 2.1, which dependency manages cassandra-driver-core:3.6.0. It's very weird that just Spring Boot 2.1 is pulling cassandra-driver-core. I'm pretty sure you're pulling also Spring Data Cassandra ...

If it's the case, please remove it, either you use Spring Data Cassandra, or you use Achilles. Having both libraries in the classpath is source of headache

timtebeek commented 5 years ago

It's 1:15 here, so pardon the short response.. :)

Have you tried to use either the spring boot parent pom file, or bom approach to get spring boot managed dependency versions? That'll get you metrics core 4.x

We're most definitely not using spring data, and will not for the foreseeable future. We really just have plain repositories and managed incompatible dependency versions with spring boot 2.1

On Fri, Jan 18, 2019, 20:19 DuyHai DOAN <notifications@github.com wrote:

@timtebeek https://github.com/timtebeek

You said I switched to Spring Boot 2.1, which dependency manages cassandra-driver-core:3.6.0. It's very weird that just Spring Boot 2.1 is pulling cassandra-driver-core. I'm pretty sure you're pulling also Spring Data Cassandra ...

If it's the case, please remove it, either you use Spring Data Cassandra, or you use Achilles. Having both libraries in the classpath is source of headache

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/doanduyhai/Achilles/issues/353#issuecomment-455658154, or mute the thread https://github.com/notifications/unsubscribe-auth/AA-tBjpLXSvpRWVf7hJSwIeXbw0YI2cYks5vEh5cgaJpZM4YgKY_ .

timtebeek commented 5 years ago

For reference: Spring Boot manages the dependency version via this line: https://github.com/spring-projects/spring-boot/blob/v2.1.2.RELEASE/spring-boot-project/spring-boot-dependencies/pom.xml#L58

doanduyhai commented 5 years ago

Ok I see, Spring Boot pom is requiring metrics-core 4.0.5 and Achilles is using an older version

What you can do is to exclude the metrics-core version of Achilles:


<dependency>
    <groupId>info.archinnov</groupId>
    <artifactId>achilles-junit</artifactId>
    <exclusions>
       <exclusion>
         <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-core</artifactId>
       <exclusion>  
    </exclusions>
</dependency>
timtebeek commented 5 years ago

hi @doanduyhai thanks, but doesn't resolve the issue. I've created a sample project here: https://github.com/timtebeek/achilles-issue-353 Which shows the issue here: https://travis-ci.org/timtebeek/achilles-issue-353/builds/483284041 Adding the suggested exclusion still triggers the issue, as te shaded cassandra-driver-core:3.5.0 still tries to acess com.codahale.metrics.JmxReporter which in 4.x has been moved to com.codahale.metrics.jmx.JmxReporter.

Hope that helps clear things up. The problem appears to lie in the shaded cassandra driver, but excluding it leads to other problems. Could you see about upgrading to the 3.6.0 driver?

doanduyhai commented 5 years ago

Ok I understand clearly the problem now.

  1. The com.datastax.driver.core.Metrics is referencing the class com.codahale.metrics.JmxReporter :
    
    import com.codahale.metrics.JmxReporter;
    ...
    ...
    if (manager.configuration.getMetricsOptions().isJMXReportingEnabled()) {
      this.jmxReporter =
          JmxReporter.forRegistry(registry).inDomain(manager.clusterName + "-metrics").build();
      this.jmxReporter.start();

 https://github.com/datastax/java-driver/blob/3.6.0/driver-core/src/main/java/com/datastax/driver/core/Metrics.java#L146

2. Spring Boot is pulling the new `metrics-core:4.x` where they move `com.codahale.metrics.JmxReporter` to `com.codahale.metrics.jmx.JmxReporter`

3. Upgrading to `com.datastax.cassandra:cassandra-driver-core:3.6.0` does not solve the issue since the source code of `com.datastax.driver.core.Metrics` has not been updated for `metrics-core:4.x`

I don't see any solution from **Achilles** side. The shaded driver core jar only shade `netty` classes, not `metrics-core` classes. You can:

* either open an issue at java driver core to ask them to upgrade to `metrics-core:4.x`
* or downgrade your Spring Boot version to an older version that uses `metrics-core:3.x`

I'm closing because it's clearly not an **Achilles** issue.
timtebeek commented 5 years ago

That's a shame, but thanks for helping walk through the issue..

For now our workaround is downgrading dropwizard metrics through:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.2.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>achilles-issue-353</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <dropwizard-metrics.version>3.2.6</dropwizard-metrics.version>
    </properties>

Note that this, for now, seems to only way of using Spring Boot 2.1 that I could find, so it might be of use for others that stumble upon this issue.

timtebeek commented 5 years ago

Though this looks promising: https://docs.datastax.com/en/developer/java-driver/3.6/manual/metrics/#metrics-4-compatibility

Weird how we're not trying to use the JMXReporter with Achilles, but still end up with the above ClassNotFound issue.

arnelandwehr commented 5 years ago

@doanduyhai Same problem here, is it possible to reopen this one and add the workaround described above. Or maybe just deactivate jmx reporting for the embedded cluster?

doanduyhai commented 5 years ago

The problem is indeed solved by this existing PR that has been already merged to master: https://github.com/doanduyhai/Achilles/commit/432db9c8f77ae2f4752ecc5ba0de03373cec3fe0

In this PR, we disable use of JMX for Embedded Achilles

I'll attempt a release of Achilles in the next days so you can have the fix

arnelandwehr commented 5 years ago

that's great, thank you!

timtebeek commented 5 years ago

new release sounds perfect; any idea when we might expect that?

doanduyhai commented 5 years ago

Achilles 6.0.1 released, will be available in a few hours on Maven Central