Bug 59556

Summary: AntClassLoader.findClassInComponents does not work with JDK9-b116+
Product: Ant Reporter: Vincent Privat <vincent.privat>
Component: CoreAssignee: Ant Notifications List <notifications>
Status: RESOLVED FIXED    
Severity: blocker    
Priority: P1    
Version: 1.9.7   
Target Milestone: 1.9.8   
Hardware: All   
OS: All   

Description Vincent Privat 2016-05-14 12:15:29 UTC
We have an Ant project that calls some Java code in build.xml as follows:

    <target name="epsg" depends="epsg-compile">
        <touch file="${epsg.output}"/>
        <java classname="BuildProjectionDefinitions" failonerror="true">
            <sysproperty key="java.awt.headless" value="true"/>
            <classpath>
                <pathelement path="${base.dir}"/>
                <pathelement path="${proj-classpath}"/>
                <pathelement path="${proj-build.dir}"/>
            </classpath>
            <arg value="${base.dir}"/>
        </java>
    </target>

the code involves reflection:

/**
 * Proj Factory that creates instances from a given class.
 */
public class ClassProjFactory implements ProjFactory {

    private final Class<? extends Proj> projClass;

    /**
     * Constructs a new {@code ClassProjFactory}.
     * @param projClass projection class
     */
    public ClassProjFactory(Class<? extends Proj> projClass) {
        this.projClass = projClass;
    }

    @Override
    public Proj createInstance() {
        Proj proj = null;
        try {
            proj = projClass.getConstructor().newInstance();
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
        return proj;
    }
}

This code works fine with Java 7, 8, and Java 9 up to build 114.

It fails with builds 116 and 118 with this stacktrace:

java.lang.NoClassDefFoundError: jdk/internal/reflect/ConstructorAccessorImpl
	at jdk.internal.misc.Unsafe.defineClass0(java.base@9-ea/Native Method)
	at jdk.internal.misc.Unsafe.defineClass(java.base@9-ea/Unsafe.java:1125)
	at jdk.internal.reflect.ClassDefiner.defineClass(java.base@9-ea/ClassDefiner.java:63)
	at jdk.internal.reflect.MethodAccessorGenerator$1.run(java.base@9-ea/MethodAccessorGenerator.java:400)
	at jdk.internal.reflect.MethodAccessorGenerator$1.run(java.base@9-ea/MethodAccessorGenerator.java:394)
	at java.security.AccessController.doPrivileged(java.base@9-ea/Native Method)
	at jdk.internal.reflect.MethodAccessorGenerator.generate(java.base@9-ea/MethodAccessorGenerator.java:393)
	at jdk.internal.reflect.MethodAccessorGenerator.generateConstructor(java.base@9-ea/MethodAccessorGenerator.java:92)
	at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(java.base@9-ea/NativeConstructorAccessorImpl.java:55)
	at jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(java.base@9-ea/DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(java.base@9-ea/Constructor.java:453)
	at org.openstreetmap.josm.data.projection.proj.ClassProjFactory.createInstance(ClassProjFactory.java:23)
	at org.openstreetmap.josm.data.projection.Projections.getBaseProjection(Projections.java:220)
	at BuildProjectionDefinitions.doInclude(BuildProjectionDefinitions.java:159)
	at BuildProjectionDefinitions.buildList(BuildProjectionDefinitions.java:78)
	at BuildProjectionDefinitions.main(BuildProjectionDefinitions.java:52)
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@9-ea/Native Method)
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@9-ea/NativeMethodAccessorImpl.java:62)
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@9-ea/DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(java.base@9-ea/Method.java:531)
	at org.apache.tools.ant.taskdefs.ExecuteJava.run(ExecuteJava.java:218)
	at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:153)
	at org.apache.tools.ant.taskdefs.Java.run(Java.java:833)
	at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:227)
	at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:136)
	at org.apache.tools.ant.taskdefs.Java.execute(Java.java:109)
	at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:293)
	at jdk.internal.reflect.GeneratedMethodAccessor4.invoke(Unknown Source)
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@9-ea/DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(java.base@9-ea/Method.java:531)
	at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
	at org.apache.tools.ant.Task.perform(Task.java:348)
	at org.apache.tools.ant.Target.execute(Target.java:435)
	at org.apache.tools.ant.Target.performTasks(Target.java:456)
	at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1405)
	at org.apache.tools.ant.Project.executeTarget(Project.java:1376)
	at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
	at org.apache.tools.ant.Project.executeTargets(Project.java:1260)
	at org.apache.tools.ant.Main.runBuild(Main.java:854)
	at org.apache.tools.ant.Main.startAnt(Main.java:236)
	at org.apache.tools.ant.launch.Launcher.run(Launcher.java:285)
	at org.apache.tools.ant.launch.Launcher.main(Launcher.java:112)
Caused by: java.lang.ClassNotFoundException: jdk.internal.reflect.ConstructorAccessorImpl
	at org.apache.tools.ant.AntClassLoader.findClassInComponents(AntClassLoader.java:1388)
	at org.apache.tools.ant.AntClassLoader.findClass(AntClassLoader.java:1337)
	at org.apache.tools.ant.AntClassLoader.loadClass(AntClassLoader.java:1095)
	at java.lang.ClassLoader.loadClass(java.base@9-ea/ClassLoader.java:419)
	... 42 more

Latest JDK 9 Early Access can be found here: https://jdk9.java.net/download/
Comment 1 Vincent Privat 2016-05-21 00:52:29 UTC
Looks caused by https://bugs.openjdk.java.net/browse/JDK-8137058 fixed in b115.
Comment 2 Vincent Privat 2016-05-21 14:51:16 UTC
Solution found: add fork="true" to java task.
Comment 3 Stefan Bodewig 2016-05-22 14:15:25 UTC
Thank you for reporting this, I'm afraid there isn't anything Ant could do. And many thanks for sharing your "fix".
Comment 4 Alan Bateman 2016-06-19 14:41:56 UTC
Someone mailed me with question about the changes in JDK 9 with a stack trace very similar to this bug report.

Does AntClassLoader have any configuration that would cause it not to delegate to the system or platform class loader for types starting with "jdk." in the name? The javadoc for its loadClass method hints that there might be configuration somewhere that determines whether it delegates or not.
Comment 5 Alan Bateman 2016-06-20 13:30:55 UTC
Vincent - would it be possible to paste in all steps to duplicate this? We can't see yet whether this is really a JDK 9 issue or not.
Comment 6 Vincent Privat 2016-06-20 21:19:35 UTC
Sure, here they are:

> echo $JAVA_HOME
/opt/jdk-9

> svn co -r 10255 https://josm.openstreetmap.de/svn/trunk josm_bug
> cd josm_bug
> ant clean dist
Comment 7 Alan Bateman 2016-06-21 10:12:32 UTC
Thanks for the reproducer. Chris Hegarty duplicated the issue and tracked it down to org.apache.tools.ant.util.JavaEnvUtils.buildJrePackages which has a hardcoded list of package prefixed for platform classes. This needs to be updated to allow jdk.** because the JDK has been using this name space since JDK 7.
Comment 8 Vincent Privat 2016-06-22 21:03:02 UTC
I have updated Chris' patch to take into account Stefan's remarks, added a test case as described in source code, and created a PR on Github:
https://github.com/apache/ant/pull/19

Hope this helps.
Cheers,
Vincent
Comment 9 Stefan Bodewig 2016-06-23 14:40:22 UTC
the pull request has been applied to the 1.9.x and master branches, the bug will be fixed in 1.9.8 and 1.10.0

Thanks!