Summary
ant's <java fork="false"> task cannot run a package-private target class: it fails with IllegalAccessException from org.apache.tools.ant.taskdefs.ExecuteJava. A public class with the same main works fine. (Separately, the task also silently does nothing without an explicit <classpath>.)
Repro (JNode all-plugins boot /full.jgz, serial agent console)
Dir: /devices/hdb1/devtest/ant1 (JFAT).
WriteHello2.java (note: class is not public):
import java.io.*;
class WriteHello2 {
public static void main(String[] a) throws Exception {
PrintWriter w = new PrintWriter(new FileWriter("/devices/hdb1/devtest/ant1/done.txt"));
w.println("ANT RAN OK");
w.close();
}
}
build.xml:
<project name="t" default="job">
<target name="job">
<java classname="WriteHello2" fork="false" failonerror="true">
<classpath location="/devices/hdb1/devtest/ant1"/>
</java>
</target>
</project>
Run ant from the dir.
Serial output:
Buildfile: build.xml
java.lang.IllegalAccessException: Class org.apache.tools.ant.taskdefs.ExecuteJava can not access a member of class WriteHello2 with modifiers "public static"
done.txt is NOT created.
Same source re-declared as public class WriteHello2 runs fine and creates done.txt.
The same package-private WriteHello2 runs fine with the shell's java WriteHello2 from that directory — the shell JavaCommand uses JCClassLoader + reflection and explicitly accepts non-public classes (mainMethod.setAccessible(true)), so the gap is in ant's reflection path.
Analysis
Ant's ExecuteJava obtains the main method and invokes it; on JNode a non-public class makes the reflective access fail with IllegalAccessException (member modifiers "public static", class not public). The shell java command handles this by calling setAccessible(true); ant appears not to (or JNode's access-check disable path fails for package-private classes).
Suggested fix
Make JNode's reflection / ant ExecuteJava path disable access checks on the target class before invoke, matching the shell's JavaCommand behavior. As a fallback, document that ant <java> target classes must be public.
Workaround
Declare any class run via ant <java> as public, and include an explicit <classpath> element.
Summary
ant's<java fork="false">task cannot run a package-private target class: it fails withIllegalAccessExceptionfromorg.apache.tools.ant.taskdefs.ExecuteJava. Apublicclass with the samemainworks fine. (Separately, the task also silently does nothing without an explicit<classpath>.)Repro (JNode all-plugins boot
/full.jgz, serial agent console)Dir:
/devices/hdb1/devtest/ant1(JFAT).WriteHello2.java(note: class is notpublic):build.xml:Run
antfrom the dir.Serial output:
done.txtis NOT created.Same source re-declared as
public class WriteHello2runs fine and createsdone.txt.The same package-private
WriteHello2runs fine with the shell'sjava WriteHello2from that directory — the shellJavaCommandusesJCClassLoader+ reflection and explicitly accepts non-public classes (mainMethod.setAccessible(true)), so the gap is in ant's reflection path.Analysis
Ant's
ExecuteJavaobtains themainmethod and invokes it; on JNode a non-public class makes the reflective access fail withIllegalAccessException(member modifiers"public static", class not public). The shelljavacommand handles this by callingsetAccessible(true); ant appears not to (or JNode's access-check disable path fails for package-private classes).Suggested fix
Make JNode's reflection / ant
ExecuteJavapath disable access checks on the target class beforeinvoke, matching the shell'sJavaCommandbehavior. As a fallback, document that ant<java>target classes must bepublic.Workaround
Declare any class run via ant
<java>aspublic, and include an explicit<classpath>element.