jdk6.0 compiler api strange behaviour (junit test case+code)

Hello,

i'm giving a first try to new jdk6 compiler api.

Consider the following test case:

import junit.framework.TestCase;

publicclass PojoCompilerTestextends TestCase{

private String pojoSrc ="public class Foo { "

+"private String name; "

+"Foo(){this.name = \"foo\";} "

+"public String getName(){return this.name;} "

+"public void setName(String name){this.name = name;} "

+"}";

private PojoCompiler pojoCompiler;

protectedvoid setUp()throws Exception{

super.setUp();

this.pojoCompiler =new PojoCompilerImpl();

}

publicvoid testCompilePojo()throws ClassNotFoundException, InstantiationException, IllegalAccessException{

Class clazz = this.pojoCompiler.compile("Foo", this.pojoSrc);

assertNotNull("Loaded class shoult not be null", clazz);

}

}

here is the class-under-test:

publicclass PojoCompilerImplimplements PojoCompiler{

private JavaCompiler compiler;

private DiagnosticCollector<JavaFileObject> diagnostic;

private StandardJavaFileManager fileManager;

public PojoCompilerImpl(){

this.compiler = ToolProvider.getSystemJavaCompiler();

this.diagnostic =new DiagnosticCollector<JavaFileObject>();

this.fileManager = this.compiler.getStandardFileManager(this.diagnostic, null,null);

}

/* (non-Javadoc)

* @see it.chi.infopipe.nr.model.output.PojoCompiler#compile(java.lang.String, java.lang.String)

*/

public Class compile(String className, String source)throws ClassNotFoundException, InstantiationException, IllegalAccessException{

JavaSourceFromString pojo =new JavaSourceFromString(className, source);

Iterable<?extends JavaFileObject> compilationUnits=

Arrays.asList(new JavaSourceFromString[]{pojo});

Iterable<String> options = Arrays.asList(new String[]{"-verbose","-Xlint"});

boolean compilationErrors =

compiler.getTask(null, fileManager, this.diagnostic, options, null, compilationUnits).call();

for (Diagnostic diagnostic : this.diagnostic.getDiagnostics()){

System.out.format("Error on line %d%s%n", diagnostic.getLineNumber(), diagnostic);

}

Class clazz = ClassLoader.getSystemClassLoader().loadClass("Foo");

clazz.newInstance();

return clazz;

}

/**

* A file object used to represent source coming from a string.

* (from javadoc)

*/

publicclass JavaSourceFromStringextends SimpleJavaFileObject{

/**

* The source code of this "file".

*/

final String code;

/**

* Constructs a new JavaSourceFromString.

* @param name the name of the compilation unit represented by this file object

* @param code the source code for the compilation unit represented by this file object

*/

JavaSourceFromString(String name, String code){

super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension),

Kind.SOURCE);

this.code = code;

}

@Override

public CharSequence getCharContent(boolean ignoreEncodingErrors){

return code;

}

}

}

the test case fails, but i don't get any compiler error shown or others. this is the ouput to stderr:

[parsing started string:///Foo.java from JavaSourceFromString]

[parsing completed 53ms]

[loading /usr/java/jdk1.6.0/lib/ct.sym(META-INF/sym/rt.jar/java/lang/Object.class)]

[loading /usr/java/jdk1.6.0/lib/ct.sym(META-INF/sym/rt.jar/java/lang/String.class)]

[checking Foo]

[loading /usr/java/jdk1.6.0/lib/ct.sym(META-INF/sym/rt.jar/java/io/Serializable.class)]

[wrote Foo.class]

[total 587ms]

i'm using :

java version "1.6.0-rc"

Java(TM) SE Runtime Environment (build 1.6.0-rc-b97)

Java HotSpot(TM) Client VM (build 1.6.0-rc-b97, mixed mode, sharing)

on linux-i586

any idea ?

thanks,

Valerio

[6497 byte] By [ervalerioa] at [2007-10-3 3:46:31]
# 1
i also discovered that the intended .class file is being correctly compiled. The problem must be in the way the class loader look for it...
ervalerioa at 2007-7-14 21:43:15 > top of Java-index,Developer Tools,Java Compiler...
# 2

also, there was a small bug (an hard-coded value):

Class clazz = ClassLoader.getSystemClassLoader().loadClass("Foo");

to be changed in

Class clazz = ClassLoader.getSystemClassLoader().loadClass(srcName);

which by the way hasn't changed anyhow the result: the classLoader is still unable to find the just-compiled class.

Message was edited by:

ervalerio

ervalerioa at 2007-7-14 21:43:15 > top of Java-index,Developer Tools,Java Compiler...
# 3

srcName isn't defined in the code you've showed.

So it can't compile.

> which by the way hasn't changed

although you changed it?

> anyhow the result: the classLoader is still unable to find the just-compiled class.

Impossible to say WTH you are talking about at this stage.

And WTF is the lone Class.forName() supposed to do?

ejpa at 2007-7-14 21:43:15 > top of Java-index,Developer Tools,Java Compiler...
# 4

sorry, one more typo. it should have been:

Class clazz = ClassLoader.getSystemClassLoader().loadClass(className);

So, the class is being correctly compiled: I can see Foo.class at the root directory of my project).

The problem doesn't come from the usage of the compiler api directly.

btw, I tried adding one compiler option so that the new class is found one classpath:

Iterable<String> options = Arrays.asList(new String[] { "-verbose", "-d target/classes" });

but seems like -d option isn't supported (yet?) :

java.lang.IllegalArgumentException: invalid flag: -d /home/schiavoni/workspace/infopipe-nr/target/classes

at com.sun.tools.javac.api.JavacTool.processOptions(JavacTool.java:236)

at com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:207)

at com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:53)

at it.chi.infopipe.nr.model.output.PojoCompilerImpl.compile(PojoCompilerImpl.java:53)

at it.chi.infopipe.nr.model.output.PojoCompilerTest.testCompilePojo(PojoCompilerTest.java:24)

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)

at junit.framework.TestCase.runTest(TestCase.java:164)

at junit.framework.TestCase.runBare(TestCase.java:130)

at junit.framework.TestResult$1.protect(TestResult.java:110)

at junit.framework.TestResult.runProtected(TestResult.java:128)

at junit.framework.TestResult.run(TestResult.java:113)

at junit.framework.TestCase.run(TestCase.java:120)

at junit.framework.TestSuite.runTest(TestSuite.java:228)

at junit.framework.TestSuite.run(TestSuite.java:223)

at org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:35)

at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)

at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

ervalerioa at 2007-7-14 21:43:15 > top of Java-index,Developer Tools,Java Compiler...
# 5

in some old pre-release (b47) there was a setOutputDirectory method on the JavaCompilerTool object (which also doesn't seem to be availabe anymore in latest mustang relealse, b97)...

(as shown here: http://www.javalobby.org/forums/thread.jspa?messageID=92038470 )

so what i need is to find a way to set the output directory for any compiled class...

Message was edited by:

ervalerio

ervalerioa at 2007-7-14 21:43:15 > top of Java-index,Developer Tools,Java Compiler...
# 6

i found my self a (ugly) workaround !

instead of using the filemanage instance passed to the compiler, i do something like:

if (compiler.getTask(null, fileManager, this.diagnostic, options, null,

compilationUnits).call()) {

File workingDir = new File(SystemUtils.USER_DIR);

URL workingDirURL = workingDir.toURI().toURL();

ClassLoader urlClassLoader = new URLClassLoader(new URL[] {workingDirURL});

clazz =

urlClassLoader.loadClass(className);

clazz.newInstance();

return clazz;

}

surely this can break somewhere/somehow..but it's a first-step !

i'll keep the duke dollars in case someone find a more elegant solution.

ervalerioa at 2007-7-14 21:43:15 > top of Java-index,Developer Tools,Java Compiler...