Re: JLink / java.io.ObjectInputStream.redObject[] - ClassNotFoundException
- To: mathgroup at smc.vnet.net
- Subject: [mg57677] Re: [mg57608] JLink / java.io.ObjectInputStream.redObject[] - ClassNotFoundException
- From: Todd Gayley <tgayley at wolfram.com>
- Date: Fri, 3 Jun 2005 05:35:10 -0400 (EDT)
- Sender: owner-wri-mathgroup at wolfram.com
Felix,
You are correct about the casue of the problem. When Java deserializes an
object, it tries to load the class of the object using the classloader that
loaded the currently-running class. When you call ois@readObject[], the
code that is performing this call is part of J/Link's internals. J/Link's
own classes are loaded by the "application" classloader, whereas all
classes loaded from CLASSPATH or J/Link-specific application directories
are loaded by J/Link's special classloader, called JLinkClassLoader. The
application classloader doesn't know about the classes that
JLinkClassLoader knows about (like the WEKA classes), so it cannot find
them when it tries to deserialize a WEKA object.
The solution is straightforward if you have followed the above line of
reasoning. Simply ensure that the Java code that is calling readObject() is
not part of J/Link itself, but is instead code that was loaded into J/Link
from CLASSPATH or other user-level locations, so that it will be loaded by
JLinkClassLoader. What this means is that you need to write a trivial class
that calls readObject():
public class Deserializer {
public static Object readObject(java.io.ObjectInputStream ois)
throws Exception {
return ois.readObject();
}
}
Put this class onto your CLASSPATH or anywhere else J/Link looks for user
classes (such as a Java application directory). Then do this:
fis = JavaNew[ "java.io.FileInputStream",
"C:\\work\\mlf_develop\\WEKA\\algorithm.mod" ];
ois = JavaNew[ "java.io.ObjectInputStream", fis ];
LoadJavaClass["Deserializer"]; (* Deserializer is now loaded by the
same classloader that loads WEKA classes. *)
algin = Deserializer`readObject[ois]
There might be another way to tell Java which classloader to use when
deserializing your objects, but this trick of creating a J/Link-loaded
utility class to do the job works nicely.
It is probably an oversight that such a utility class is not built into
J/Link (of course, we would have to make sure that this class was loaded by
JLinkClassLoader like user classes are, not like the other internal parts
of J/Link). Perhaps this will be added in the future.
Todd Gayley
Wolfram Research
At 04:16 AM 6/2/2005, Felix Kossak wrote:
>Hi,
>
>I have a little trouble with reading a Java object from file which I
>have myself serialized before (from the Mathematica environment). It
>works when I write a respective Java class by hand and execute it from
>command line, but the same code does not work within Mathematica - it
>produces a ClassNotFoundException.
>
>Does anyone here have respective experience with serializing /
>deserializing objects using J/Link?
>
>The point seems to be that I use an extra Java library (WEKA), which
>works perfectly for every other code I have tried so far, including
>serializing, just not for deserializing. But it cannot be WEKA's fault
>(as it works in another environment) - the class loader used in J/Link
>seems to be the problem.
>
>Here is some of the context and code:
>-------------------------------------
>
>InstallJava[
> CommandLine -> "C:\\Program Files\\Java\\j2re1.4.2\\bin\\java.exe
> -Xmx400m",
> ClassPath -> ".;C:\\Program Files\\Weka\\Weka-3-4\\weka.jar"
>];
>
>(Weka 3.4 provides the extra Java library I use)
>
>This, amongst others, works:
>----------------------------
>
>algorithm = JavaNew[
> "weka.classifiers.functions.MultilayerPerceptron" ];
>algorithm@buildClassifier[ wekaDataSet ];
>
>...
>
>os = JavaNew[
> "java.io.FileOutputStream",
> "C:\\work\\mlf_develop\\WEKA\\algorithm.mod"
>];
>oos = JavaNew[ "java.io.ObjectOutputStream", os ];
>oos@writeObject[ algorithm ];
>oos@flush[];
>oos@close[];
>
>This, however, fails:
>=====================
>
>fis = JavaNew[
> "java.io.FileInputStream",
> "C:\\work\\mlf_develop\\WEKA\\algorithm.mod"
>];
>ois = JavaNew[ "java.io.ObjectInputStream", fis ];
>
>algin = ois@readObject[]
>
>It produces the following error messages:
>-----------------------------------------
>
>Java::excptn: A Java exception occurred: java.lang.ClassNotFoundException: \
>weka.classifiers.functions.MultilayerPerceptron
> at java.net.URLClassLoader$1.run(Unknown Source)
> at java.security.AccessController.doPrivileged(Native Method)
> at java.net.URLClassLoader.findClass(Unknown Source)
> at java.lang.ClassLoader.loadClass(Unknown Source)
> at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
> at java.lang.ClassLoader.loadClass(Unknown Source)
> at java.lang.ClassLoader.loadClassInternal(Unknown Source)
> at java.lang.Class.forName0(Native Method)
> at java.lang.Class.forName(Unknown Source)
> at java.io.ObjectInputStream.resolveClass(Unknown Source)
> at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
> at java.io.ObjectInputStream.readClassDesc(Unknown Source)
> at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
> at java.io.ObjectInputStream.readObject0(Unknown Source)
> at java.io.ObjectInputStream.readObject(Unknown Source)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
> at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source).
>
>$Failed
>
>I also tried to instantiate the variable 'algin' before reading:
>
>algin = JavaNew[ "weka.classifiers.functions.MultilayerPerceptron" ];
>
>but that doesn't help either.
>
>
>Thanks a lot for any help,
>Felix