-
Bug
-
Resolution: Unresolved
-
Critical
-
None
-
11.0.9.Final
-
None
-
Undefined
If a remote cache operation returns exceptionally, the chain of exception causes can easily contain an exception class not known to Infinispan's classloader.
This causes a ClassNotFoundException during unmarshalling of the ExceptionResponse object, which obscure the root cause of the cache operation failure.
e.g.
2021-02-17 17:02:27,340 ERROR [org.infinispan.CLUSTER] (thread-14,ejb,wildfly3) ISPN000475: Error processing response for request 1285 from wildfly2: java.lang.ClassNotFoundException: javax.resource.ResourceException from [Module "org.infinispan" version 11.0.8.Final-redhat-00001 from local module loader @5f031ebd (finder: local module finder @4ee37ca3 (roots: /tmp/tests-clustering/jboss-eap-3/modules,/tmp/tests-clustering/jboss-eap-3/modules/system/layers/base))] at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:255) at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:410) at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398) at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:116) at java.base/java.lang.Class.forName0(Native Method) at java.base/java.lang.Class.forName(Class.java:315) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.exts.ThrowableExternalizer.readGenericThrowable(ThrowableExternalizer.java:278) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.exts.ThrowableExternalizer.readObject(ThrowableExternalizer.java:259) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.exts.ThrowableExternalizer.readObject(ThrowableExternalizer.java:42) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readWithExternalizer(GlobalMarshaller.java:728) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readNonNullableObject(GlobalMarshaller.java:709) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readNullableObject(GlobalMarshaller.java:358) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.BytesObjectInput.readObject(BytesObjectInput.java:32) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.exts.ThrowableExternalizer.readGenericThrowable(ThrowableExternalizer.java:276) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.exts.ThrowableExternalizer.readObject(ThrowableExternalizer.java:259) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.exts.ThrowableExternalizer.readObject(ThrowableExternalizer.java:42) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readWithExternalizer(GlobalMarshaller.java:728) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readNonNullableObject(GlobalMarshaller.java:709) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readNullableObject(GlobalMarshaller.java:358) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.BytesObjectInput.readObject(BytesObjectInput.java:32) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.exts.ThrowableExternalizer.readGenericThrowable(ThrowableExternalizer.java:276) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.exts.ThrowableExternalizer.readObject(ThrowableExternalizer.java:259) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.exts.ThrowableExternalizer.readObject(ThrowableExternalizer.java:42) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readWithExternalizer(GlobalMarshaller.java:728) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readNonNullableObject(GlobalMarshaller.java:709) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readNullableObject(GlobalMarshaller.java:358) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.BytesObjectInput.readObject(BytesObjectInput.java:32) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.exts.ThrowableExternalizer.readObject(ThrowableExternalizer.java:233) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.exts.ThrowableExternalizer.readObject(ThrowableExternalizer.java:42) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readWithExternalizer(GlobalMarshaller.java:728) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readNonNullableObject(GlobalMarshaller.java:709) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readNullableObject(GlobalMarshaller.java:358) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.BytesObjectInput.readObject(BytesObjectInput.java:32) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.remoting.responses.ExceptionResponse$Externalizer.readObject(ExceptionResponse.java:49) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.remoting.responses.ExceptionResponse$Externalizer.readObject(ExceptionResponse.java:41) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readWithExternalizer(GlobalMarshaller.java:728) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readNonNullableObject(GlobalMarshaller.java:709) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.readNullableObject(GlobalMarshaller.java:358) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.objectFromObjectInput(GlobalMarshaller.java:192) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.marshall.core.GlobalMarshaller.objectFromByteBuffer(GlobalMarshaller.java:221) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.remoting.transport.jgroups.JGroupsTransport.processResponse(JGroupsTransport.java:1394) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.remoting.transport.jgroups.JGroupsTransport.processMessage(JGroupsTransport.java:1305) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.remoting.transport.jgroups.JGroupsTransport.access$300(JGroupsTransport.java:131) at org.infinispan@11.0.8.Final-redhat-00001//org.infinispan.remoting.transport.jgroups.JGroupsTransport$ChannelCallbacks.up(JGroupsTransport.java:1445)
After discussing the issue with remerson@redhat.com, we can up with a couple of options for how to handle this:
For the short-term (i.e. 11.0.x), we can handle any ClassNotFoundException thrown during unmarshalling of a generic throwable (i.e. org.infinispan.marshall.exts.ThrowableExternalizer.readGenericThrowable(....)) by returning a RuntimeException whose message contains the message of the original exception, as well as the FQCN of the exception class that could not be resolved.
In the medium term, I suggested allowing the ThrowableExternalizer to be constructed with a means for resolving classes, e.g. AdvancedExternalizer<ClassLoader>, whose default implementation writes nothing, and when reading returns the ClassLoader associated with the GlobalConfiguration. The marshalling of a generic throwable will then look something like:
private final AdvancedExternalizer<ClassLoader> classLoaderExternalizer; private void writeGenericThrowable(ObjectOutput out, Throwable t) throws IOException { Class<?> exceptionClass = t.getClass(); out.writeUTF(exceptionClass.getName()); this.classLoaderExternalizer.writeObject(out, exceptionClass.getClassLoader()); writeMessageAndCause(out, t); } private Throwable readGenericThrowable(ObjectInput in) throws IOException, ClassNotFoundException { String impl = in.readUTF(); ClassLoader loader = this.classLoaderExternalizer.read(in); String msg = MarshallUtil.unmarshallString(in); Throwable t = (Throwable) in.readObject(); try { Class<?> clazz = loader.loadClass(impl); if (t == null && msg == null) { return (Throwable) clazz.getConstructor().newInstance(new Object[]{}); } else if (t == null) { return (Throwable) clazz.getConstructor(String.class).newInstance(msg); } else if (msg == null) { return (Throwable) clazz.getConstructor(Throwable.class).newInstance(t); } return (Throwable) clazz.getConstructor(String.class, Throwable.class).newInstance(msg, t); } catch (IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e) { throw new MarshallingException(e); } }
In the long-term, this stuff will be replaced by ProtoStream, though that mechanism should still provide a means for overriding how a given exception class is resolved.
- is related to
-
ISPN-12609 ClassNotFoundException: org.jboss.marshalling.TraceInformation
- New
-
ISPN-11022 Remote exception stack traces are not serialized
- Closed
- relates to
-
ISPN-13467 ThrowableExternalizer cannot handle NullPointerException with cause
- To Do