Search code examples
javaspringosgideserializationclassloader

org.apache.commons.lang.SerializationException: java.lang.ClassNotFoundException


I am using org.apache.commons.lang.SerializationUtils, but i got an error. i am a Java newbie if you need more information, please let me know code:

Profile profile2 = new Profile();
profile2.setFileName(path);
profile2.setStatus("UPLOADED");
byte[] payload2 = SerializationUtils.serialize(profile2);
profile = (Profile) SerializationUtils.deserialize(payload2);

run time Error output:

org.apache.commons.lang.SerializationException: java.lang.ClassNotFoundException: com.xxx.xxx.Profile
        at org.apache.commons.lang.SerializationUtils.deserialize(SerializationUtils.java:166)
        at org.apache.commons.lang.SerializationUtils.deserialize(SerializationUtils.java:193)

people says Profile is not in classpath. if that was true, error would happen on "new Profile()". am I right?

I just found a workaround:

profile = (EveSuccessCriteriaProfile) SerializationUtils.deserialize(payload2);

replaced by

InputStream fis = null;
fis = new ByteArrayInputStream(payload2);
ObjectInputStream o = new ObjectInputStream(fis);
profile = (Profile) o.readObject();

it works fine


Solution

  • The problem is that in OSGi there is not only once classloader that loaded all classes. There is one classloader per bundle. So if you do Profile.class.getClassLoader() you will get the classloader of the bundle that contains Profile. If you do SerializationUtils.class.getClassLoder() then you will get the classloader of the commons.lang bundle. As commons.lang does not have an Import-Package for your the package Profile is in it will not see it. So if SerializationUtils.deserialize uses its own classloader to load the Profile class it will not find it.

    I am pretty sure it will then try to use the ThreadContext classloader to load the user class. So it might help to do Thread.currentThread().setContextClassLoader(Profile.class.getClassLoader()); before the calls to SerializationUtils.deserialize.

    This is only a workaround though. The deserialize call should be enhanced to accept a ClassLoader as a second argument. So dont get into the habbit to see the ContextClassLoader as a best practice.

    Unfortunately SerializationUtils simply does not work in OSGi. You will have to wait for this issue to be resolved: https://issues.apache.org/jira/browse/LANG-1049

    You should try with https://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/input/ClassLoaderObjectInputStream.html that should allow to do the deserialization cleanly without buddy classloading or similar.