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