Reputation: 1452
I have a webapp which saves state in the client side. State is accumulated into an Object []
Object state[] = new Object[10];
state[0] = _parent_s_state_array
state[1] = _some_int;
state[2] = _some_POJO;
..
..
then it is
In next request this serialized state is submitted back and we reverse the steps to reconstruct state in serverside. This strategy is working fine for several hundred pages.
But for a certain page using a specific POJO with few String properties, I am getting a ClassNotFoundException
while deserialization. It is to be noted that object of the same class was created and serialized few moments ago in the same JVM session so we can rule out that Class not being present in classpath.
Some more observations
WEB-INF/classes/com/xxx/yyy/
Can somebody provide some pointers/strategy towards debugging this issue.
Thanks in advance.
Exception
ERROR [[ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'] ClassNotFoundException occured restoring StateManager state from serialized form
java.lang.ClassNotFoundException: com.xxx.yyy.TimeParameters
at java.net.URLClassLoader$1.run(URLClassLoader.java:366) ~[na:1.7.0_65]
at java.net.URLClassLoader$1.run(URLClassLoader.java:355) ~[na:1.7.0_65]
at java.security.AccessController.doPrivileged(Native Method) ~[na:1.7.0_65]
at java.net.URLClassLoader.findClass(URLClassLoader.java:354) ~[na:1.7.0_65]
at java.lang.ClassLoader.loadClass(ClassLoader.java:425) ~[na:1.7.0_65]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) ~[na:1.7.0_65]
at java.lang.ClassLoader.loadClass(ClassLoader.java:358) ~[na:1.7.0_65]
at java.lang.Class.forName0(Native Method) [na:1.7.0_65]
at java.lang.Class.forName(Class.java:270) [na:1.7.0_65]
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:625) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1612) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1517) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370) ~[na:1.7.0_65]
at org.apache.commons.collections.map.AbstractHashedMap.doReadObject(AbstractHashedMap.java:1212) ~[weblogic.server.merged.jar:12.1.3.0.0]
at org.apache.commons.collections.map.CaseInsensitiveMap.readObject(CaseInsensitiveMap.java:149) ~[weblogic.server.merged.jar:12.1.3.0.0]
Class
package com.xxx.yyy;
public class TimeParameters implements Serializable {
/**
*
*/
private static final long serialVersionUID = 5384703411813811209L;
private String yr;
private String qtr;
private String mth;
private String analysisType;
// Getters and Setters
...
...
}
Upvotes: 0
Views: 1433
Reputation: 1452
TLDR;
A class from Apache Commons collections was involved somewhere during serialization. Since apache-commons-collections was loaded from Weblogic jars, it caused required class searched in Application classloader where it could not be found. Fix was to add org.apache.commons.collections.*
to prefer-application-packages
in weblogic.xml
Details
I did a remote debugger session to trace to a call to Class.forName0(String className, boolean, ClassLoader loader)
.
Found that when the required class could be loaded, the classloader passed had a deeper hierarchy
this contains all classes in WEB-INF/classes --> weblogic.utils.classloaders.ChangeAwareClassLoader@6437e3af finder: weblogic.utils.classloaders.CodeGenClassFinder@2cd01c0c annotation: mi.8200@MedicalIntelligence
weblogic.utils.classloaders.FilteringClassLoader@6413df9c finder: weblogic.utils.classloaders.CodeGenClassFinder@54bdae18 annotation:
weblogic.utils.classloaders.GenericClassLoader@5919d25d finder: weblogic.utils.classloaders.CodeGenClassFinder@1265cb83 annotation:
java.net.URLClassLoader@5a88cbff
Application classloader, contains classes from weblogic bundled jars --> sun.misc.Launcher$AppClassLoader@2a9a42ef
sun.misc.Launcher$ExtClassLoader@75a06ec2
And when it threw ClassNotFoundException
it was cut short -- only last two entries were present
sun.misc.Launcher$AppClassLoader@2a9a42ef <-- Hierarchy starts at Application classloader
sun.misc.Launcher$ExtClassLoader@75a06ec2
Then, I noticed that the stacktrace contained these lines ending with ~[weblogic.server.merged.jar:12.1.3.0.0]
(edited question to add more stacktrace)
at org.apache.commons.collections.map.AbstractHashedMap.doReadObject(AbstractHashedMap.java:1212) ~[weblogic.server.merged.jar:12.1.3.0.0]
at org.apache.commons.collections.map.CaseInsensitiveMap.readObject(CaseInsensitiveMap.java:149) ~[weblogic.server.merged.jar:12.1.3.0.0]
So Apache commons collections was being loaded from weblogic bundled jars ie sun.misc.Launcher$AppClassLoader@2a9a42ef
which might have triggered wrong classloader to be passed further down the line. So added org.apache.commons.collections.*
to prefer-application-packages
in weblogic.xml
<prefer-application-packages>
...
<package-name>org.apache.commons.collections.*</package-name>
</prefer-application-packages>
Useful resources
http(s)://<server-hostname:port>/wls-cat
, shows Classloader treeUpvotes: 1
Reputation: 12367
Java serialization is not the best way to accomplish your task. You will be better off to serialize it into (say) JSON and then compress it if you like. Good choice would be google GSON. Or XStream with JSON Driver. Or Jackson ...
Upvotes: 0