3

I have a program where I compile java code that somebody writes in a text box, and run it. They type out the full source code, class and all

I save the class they write to a random java source file, and then compile and load the class through a classloader. This works perfectly.

I have a new issue though, that of sub classes. I give the outer class a unique name, and load that class.

Ex.

TEMP1110.java -> TEMP1110.class, etc. With inner classes, it compiles to TEMP1110$InnerClass.class I try loading this class through my class loader, but when the outer class makes a call to it: new InnerClass().method();

it gives me this: java.lang.NoClassDefFoundError: TEMP1110$InnerClass

Is there some quirk or something I am doing wrong?

My classloader:

private static class JClassLoader extends ClassLoader {
    public Class buildClass(final byte[] data, final String className) {
        return (Class) defineClass(className, data, 0, data.length);
    }
}

className being TEMPCLASS$InnerClass, and data being the bytes that represent the class file. This works for outer classes.

kazoo
  • 137
  • 2
  • 7
  • 1
    Stupid point, but you've put "it compiles to `TEMP1110$InnerClass.java`." Is that a mistype, or is the issue that it needs to be .class and it's got the wrong file name? – Michael Berry Aug 02 '11 at 19:17
  • If the inner class isn't static, won't you need to load the outer class first? See here: http://stackoverflow.com/questions/2868337/java-how-to-load-a-class-and-its-inner-classes-that-is-already-on-the-class-pa – Michael Berry Aug 02 '11 at 19:37

3 Answers3

0

I suppose 'new InnerClass()' uses normal classloading and classpath search to Find classes. Since your generated .class file is not on classpath it can not be found.

Try dynamically manipulating classpath to add your folder where your .class files reside:

String currentPath = System.getProperty("java.library.path");
System.setProperty( "java.library.path", current + ":/path/to/my/classfiles" );

// this forces JVM to reload "java.library.path" property
Field fieldSysPath = ClassLoader.class.getDeclaredField( "sys_paths" );
fieldSysPath.setAccessible( true );
fieldSysPath.set( null, null );
Peter Knego
  • 79,991
  • 11
  • 123
  • 154
0

From the API spec, it looks like the NoClassDefFoundError is thrown when the name that you send to defineClass does not match the binary name of the class represented by bytes.

You could try passing null for the className for the inner class.

Kal
  • 24,724
  • 7
  • 65
  • 65
0

My eventual solution, with I being the interface:

ClassLoader cl = new URLClassLoader(new URL[] {new File("TEMP/").toURI().toURL()});
Class classd = cl.loadClass(className);
return (I) classd.newInstance();

Previously, I was using some older documentation that just complicated the whole process.

kazoo
  • 137
  • 2
  • 7