Jynx 0.3 – how to fix custom class loaders for use with Jython
Broken class loaders
Jynx 0.2 contained an ugly workaround for a bug I couldn’t fix for quite a while. The bug can be described as follows: suppose you defined code of a Java class A and compiled it dynamically:
A = JavaCompiler().createClass("A", A_source)
When you attempt to build a subclass
class B(A): passa NoClassDefFoundError exception was raised:
Traceback (most recent call last): File "C:\lang\Jython\jcompile.py", line 185, in <module> class B(A):pass at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:621) at java.lang.ClassLoader.defineClass(ClassLoader.java:466) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) java.lang.NoClassDefFoundError: org/python/core/PyProxy (wrong name: A)
In that case the Jython runtime failed to create a proxy class for B while locating PyProxy which is a Jython core interface. From the traceback it wasn’t clear how to locate the error and I started to debug into Jython from Netbeans.
This is what happened: Jynx defines a ByteClassLoader class which is custom class loader for dynamic compilation of A. When A is loaded with loadClass a findClass method is called to locate A and this method had to be overwritten. The ByteClassLoader was bound to A automatically and used by Jython to locate interfaces such as org.python.core.PyProxy. This didn’t work and explains the failure. A possible fix is to respond to classes which cannot be dealt with from ByteClassLoader and delegate a findClass call to the parent class loader.
Curiously Jython stopped using ByteClassLoader after I changed the inheritance hierarchy from
class ByteClassLoader(ClassLoader): def __init__(self, code): super(ByteClassLoader, self).__init__(ClassLoader.getClassLoader()) ...
class ByteClassLoader(URLClassLoader): def __init__(self, code): super(ByteClassLoader, self).__init__(, ClassLoader.getSystemClassLoader()) ...
The URLClassLoader provides the opportunity to add URLs at runtime and therefore modifying the CLASSPATH dynamically.
No disk dumps in Jynx 0.3
Prior to Jynx 0.3 a workaround has been dumping A to disk and load the class from there. We discussed the subtle nuances of selecting the right class loader and loading A from disk moved the machinery into a correct state. This wasn’t only cumbersome but a hurdle when a programmer intended to work within a Java sandbox. With Jynx 0.3 I feel prepared to explore Java integration with Jynx on GAE-J.