quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.82k stars 2.69k forks source link

ClassNotFound exception in quarkus dev when using Serialization #43111

Closed lordofthejars closed 2 months ago

lordofthejars commented 2 months ago

Describe the bug

I am using a library that uses java.io.ObjectInput and java.io.ObjectOutput to serialize some objects.

The application packaged in a JAR works, but if I run it with quarkus dev, I get a java.lang.ClassNotFoundException.

The full-stack trace:

java.lang.ClassNotFoundException: org.acme.weather.DailyWeatherData
    at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:506)
    at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:481)
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:534)
    at java.base/java.lang.Class.forName(Class.java:513)
    at java.base/java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:804)
    at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2061)
    at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1927)
    at java.base/java.io.ObjectInputStream.readClass(ObjectInputStream.java:1900)
    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1733)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:540)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:498)
    at org.bsc.langgraph4j.serializer.BaseSerializer.readObjectWithSerializer(BaseSerializer.java:59)
    at org.bsc.langgraph4j.serializer.MapSerialize.read(MapSerialize.java:70)
    at org.bsc.langgraph4j.serializer.StateSerializer.read(StateSerializer.java:21)
    at org.bsc.langgraph4j.serializer.StateSerializer.read(StateSerializer.java:7)
    at org.bsc.langgraph4j.serializer.Serializer.readObject(Serializer.java:58)
    at org.bsc.langgraph4j.serializer.Serializer.cloneObject(Serializer.java:64)
    at org.bsc.langgraph4j.CompiledGraph.cloneState(CompiledGraph.java:201)
    at org.bsc.langgraph4j.CompiledGraph.streamData(CompiledGraph.java:237)
    at org.bsc.langgraph4j.CompiledGraph.lambda$stream$19(CompiledGraph.java:328)
    at org.bsc.langgraph4j.utils.TryConsumer.accept(TryConsumer.java:13)
    at org.bsc.async.AsyncGeneratorQueue.lambda$of$0(AsyncGeneratorQueue.java:86)
    at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1423)
    at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387)
    at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312)
    at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843)
    at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808)
    at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188)

The code is https://github.com/lordofthejars-ai/quarkus-langgraph-examples/tree/main/weather-graph

Expected behavior

Service works without any exception

Actual behavior

An exception is thrown.

How to Reproduce?

Start the service with quarkus dev and curl localhost:8080/weather

Output of uname -a or ver

Darwin Kernel Version 21.6.0

Output of java -version

openjdk version "21.0.1" 2023-10-17 LTS

Quarkus version or git rev

3.14.2

Build tool (ie. output of mvnw --version or gradlew --version)

apache-maven-3.9.8

Additional information

No response

geoand commented 2 months ago

This is very likely a problem in langgraph4j, but it would require some investigation

gsmet commented 2 months ago

My guess is that it tries to load the class from the base runtime class loader where the langgraph4j classes are instead of the child runtime one where your app classes are.

The TCCL should be used to load the classes to make sure layered class loaders are supported.

Unfortunately, the JDK serialization API is quite limited in this regard thus why things like https://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/input/ClassLoaderObjectInputStream.html exist.

In any case, that’s not something we can fix in Quarkus as the dev mode layered class loader infrastructure is here to stay.

Note that the problem is not limited to Quarkus, any project using a layered class loader where the langgraph4j classes are in a different class loader as the class you load will have this issue.

It will require an upstream fix.