1

I am working on a task to migrate Quarkus from 1.x to 2.x and Quarkus integration with embedded Cassandra failed in unit testing with error -

Caused by: java.lang.IllegalArgumentException: Can't find class com.mind.common.connectors.cassandra.CassandraCustomRetryPolicy (specified by advanced.retry-policy.class)

                    **Custom retry policy**

public class CassandraCustomRetryPolicy implements RetryPolicy {

    public CassandraCustomRetryPolicy(DriverContext context, String profileName) {
    }
 //override methods
}

               ****quarkus test be like** -**

@QuarkusTest
@QuarkusTestResource(CassandraTestResource.class)
class Test {}


       **CassandraTestResource class start the embedded cassandra** 



 public class CassandraTestResource implements QuarkusTestResourceLifecycleManager {
    
        private Cassandra cassandra;
    
        @Override
        public Map<String, String> start() {
            cassandra = new CassandraBuilder().version("3.11.9")
                    .addEnvironmentVariable("JAVA_HOME", getJavaHome())
                    .addJvmOptions("-Xms512M -Xmx512m").build();
    
            cassandra.start();
    }

I have override the default Cassandra driver policy in application.conf inside resource folder.

  datastax-java-driver {
          basic.request {
            timeout = ****
            consistency = ***
            serial-consistency = ***
          }
          advanced.retry-policy {
            class = com.mind.common.connectors.cassandra.CassandraCustomRetryPolicy
          }

I have observed that my custom retry policy class comes under banned resource in QuarkusClassLoader.java-

String resourceName = sanitizeName(name).replace('.', '/') + ".class";
                boolean parentFirst = parentFirst(resourceName, state);
                if (state.bannedResources.contains(resourceName)) {
                    throw new ClassNotFoundException(name);
                }

I have captured the following logs -

java.lang.ClassNotFoundException: com.mind.common.connectors.cassandra.CassandraCustomRetryPolicy at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:438) at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:414) at java.base/java.lang.Class.forName0(Native Method) at java.base/java.lang.Class.forName(Class.java:315) at com.datastax.oss.driver.internal.core.util.Reflection.loadClass(Reflection.java:57) at com.datastax.oss.driver.internal.core.util.Reflection.resolveClass(Reflection.java:288) at com.datastax.oss.driver.internal.core.util.Reflection.buildFromConfig(Reflection.java:235) at com.datastax.oss.driver.internal.core.util.Reflection.buildFromConfigProfiles(Reflection.java:194) at com.datastax.oss.driver.internal.core.context.DefaultDriverContext.buildRetryPolicies(DefaultDriverContext.java:359) at com.datastax.oss.driver.internal.core.util.concurrent.LazyReference.get(LazyReference.java:55) at com.datastax.oss.driver.internal.core.context.DefaultDriverContext.getRetryPolicies(DefaultDriverContext.java:761) at com.datastax.oss.driver.internal.core.session.DefaultSession$SingleThreaded.init(DefaultSession.java:339) at com.datastax.oss.driver.internal.core.session.DefaultSession$SingleThreaded.access$1100(DefaultSession.java:300) at com.datastax.oss.driver.internal.core.session.DefaultSession.lambda$init$0(DefaultSession.java:146) at io.netty.util.concurrent.PromiseTask.runTask(PromiseTask.java:98) at io.netty.util.concurrent.PromiseTask.run(PromiseTask.java:106) at io.netty.channel.DefaultEventLoop.run(DefaultEventLoop.java:54) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:834)

I am using quarkus version 2.7.2.Final with cassandra driver version 4.14.0

CoreThought
  • 113
  • 6
  • 16

2 Answers2

0

It's not a complete answer but I wanted to leave some notes here in case anybody else can get this over the finish line before I get back to it.

The underlying problem here is that in the Quarkus test case described above the Java driver code is loaded by the QuarkusClassLoader which (a) is more restrictive about where it loads code from and (b) doesn't appear to immediately support calling it's parent if necessary. So in this case executing the following in the test will fail with a ClassNotFoundException:

CqlSession.class.getClassLoader().forName(customretrypolicyclassname)

while the following works without issue:

CqlSession.class.getClassLoader().getParent().forName(customretrypolicyclassname)

The class loader used to load CqlSession is the QuarkusClassLoader instance while it's parent is a stock JVM class loader.

The Java driver uses Class.forName() to load the classes specified for this policy. But since the Quarkus class loader is used to load the driver code itself that's the loader that's used for these reflection ops... and as mentioned above that driver has some specific characteristics that make loading external code harder.

absurdfarce
  • 181
  • 2
  • Thanks! you investigation is align with the issue that I am facing. I have added additional comments and logs. This is Quarkus API loading retry policy class if I delete my custom retry policy from application.conf then it will load the DeafultRetryPolicy by default . How I can make my custom retry policy part of the system. If I load the custom policy with the help of above code code sample still default retry policy attached with CQL session. – CoreThought Apr 14 '22 at 05:27
  • Note : This was working fine in quarkus 1.X – CoreThought Apr 14 '22 at 05:34
0

It worked after I initialized CQL session like -

CqlSession.builder() .addContactPoint(new InetSocketAddress(settings.getAddress(), settings.getPort())) .withLocalDatacenter("***") . withClassLoader(Thread.currentThread().getContextClassLoader()).build())

CoreThought
  • 113
  • 6
  • 16