git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@796647 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -789,6 +789,14 @@ Other changes: | |||||
| task's (compiler) adapter class. | task's (compiler) adapter class. | ||||
| Bugzilla Issue 11143. | Bugzilla Issue 11143. | ||||
| * A new subclass org.apache.tools.ant.loader.AntClassLoader5 of | |||||
| AntClassLoader has been added which overrides getResources | |||||
| which became non-final in ClassLoader with Java5+ so | |||||
| this method now behaves as expected. | |||||
| The new subclass will be used by Ant internally if it is available | |||||
| and Ant is running on Java5 or more recent. | |||||
| Bugzilla Issue 46752. | |||||
| Changes from Ant 1.7.0 TO Ant 1.7.1 | Changes from Ant 1.7.0 TO Ant 1.7.1 | ||||
| ============================================= | ============================================= | ||||
| @@ -175,6 +175,7 @@ | |||||
| <or> | <or> | ||||
| <filename name="${taskdefs.package}/AptTest*"/> | <filename name="${taskdefs.package}/AptTest*"/> | ||||
| <filename name="${util.package}/java15/*"/> | <filename name="${util.package}/java15/*"/> | ||||
| <filename name="${ant.package}/loader/*5*"/> | |||||
| </or> | </or> | ||||
| </selector> | </selector> | ||||
| @@ -46,6 +46,7 @@ import org.apache.tools.ant.util.CollectionUtils; | |||||
| import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
| import org.apache.tools.ant.util.JavaEnvUtils; | import org.apache.tools.ant.util.JavaEnvUtils; | ||||
| import org.apache.tools.ant.util.LoaderUtils; | import org.apache.tools.ant.util.LoaderUtils; | ||||
| import org.apache.tools.ant.util.ReflectUtil; | |||||
| import org.apache.tools.ant.util.VectorSet; | import org.apache.tools.ant.util.VectorSet; | ||||
| import org.apache.tools.ant.launch.Locator; | import org.apache.tools.ant.launch.Locator; | ||||
| @@ -910,6 +911,19 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { | |||||
| return url; | return url; | ||||
| } | } | ||||
| /** | |||||
| * Finds all the resources with the given name. A resource is some | |||||
| * data (images, audio, text, etc) that can be accessed by class | |||||
| * code in a way that is independent of the location of the code. | |||||
| * | |||||
| * <p>Would override getResources if that wasn't final in Java | |||||
| * 1.4.</p> | |||||
| */ | |||||
| public Enumeration/*<URL>*/ getNamedResources(String name) | |||||
| throws IOException { | |||||
| return findResources(name, false); | |||||
| } | |||||
| /** | /** | ||||
| * Returns an enumeration of URLs representing all the resources with the | * Returns an enumeration of URLs representing all the resources with the | ||||
| * given name by searching the class loader's classpath. | * given name by searching the class loader's classpath. | ||||
| @@ -920,14 +934,34 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { | |||||
| * @exception IOException if I/O errors occurs (can't happen) | * @exception IOException if I/O errors occurs (can't happen) | ||||
| */ | */ | ||||
| protected Enumeration/*<URL>*/ findResources(String name) throws IOException { | protected Enumeration/*<URL>*/ findResources(String name) throws IOException { | ||||
| return findResources(name, true); | |||||
| } | |||||
| /** | |||||
| * Returns an enumeration of URLs representing all the resources with the | |||||
| * given name by searching the class loader's classpath. | |||||
| * | |||||
| * @param name The resource name to search for. | |||||
| * Must not be <code>null</code>. | |||||
| * @param parentHasBeenSearched whether ClassLoader.this.parent | |||||
| * has been searched - will be true if the method is (indirectly) | |||||
| * called from ClassLoader.getResources | |||||
| * @return an enumeration of URLs for the resources | |||||
| * @exception IOException if I/O errors occurs (can't happen) | |||||
| */ | |||||
| protected Enumeration/*<URL>*/ findResources(String name, | |||||
| boolean parentHasBeenSearched) | |||||
| throws IOException { | |||||
| Enumeration/*<URL>*/ mine = new ResourceEnumeration(name); | Enumeration/*<URL>*/ mine = new ResourceEnumeration(name); | ||||
| Enumeration/*<URL>*/ base; | Enumeration/*<URL>*/ base; | ||||
| if (parent != null && parent != getParent()) { | |||||
| if (parent != null && (!parentHasBeenSearched || parent != getParent())) { | |||||
| // Delegate to the parent: | // Delegate to the parent: | ||||
| base = parent.getResources(name); | base = parent.getResources(name); | ||||
| // Note: could cause overlaps in case ClassLoader.this.parent has matches. | |||||
| // Note: could cause overlaps in case | |||||
| // ClassLoader.this.parent has matches and | |||||
| // parentHasBeenSearched is true | |||||
| } else { | } else { | ||||
| // ClassLoader.this.parent is already delegated to from | |||||
| // ClassLoader.this.parent is already delegated to for example from | |||||
| // ClassLoader.getResources, no need: | // ClassLoader.getResources, no need: | ||||
| base = new CollectionUtils.EmptyEnumeration(); | base = new CollectionUtils.EmptyEnumeration(); | ||||
| } | } | ||||
| @@ -1456,6 +1490,22 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { | |||||
| return "AntClassLoader[" + getClasspath() + "]"; | return "AntClassLoader[" + getClasspath() + "]"; | ||||
| } | } | ||||
| private static Class subClassToLoad = null; | |||||
| private static final Class[] CONSTRUCTOR_ARGS = new Class[] { | |||||
| ClassLoader.class, Project.class, Path.class, Boolean.TYPE | |||||
| }; | |||||
| static { | |||||
| if (JavaEnvUtils.isAtLeastJavaVersion(JavaEnvUtils.JAVA_1_5)) { | |||||
| try { | |||||
| subClassToLoad = | |||||
| Class.forName("org.apache.tools.ant.loader.AntClassLoader5"); | |||||
| } catch (ClassNotFoundException e) { | |||||
| // this is Java5 but the installation is lacking our subclass | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | /** | ||||
| * Factory method | * Factory method | ||||
| */ | */ | ||||
| @@ -1463,6 +1513,15 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { | |||||
| Project project, | Project project, | ||||
| Path path, | Path path, | ||||
| boolean parentFirst) { | boolean parentFirst) { | ||||
| if (subClassToLoad != null) { | |||||
| return (AntClassLoader) | |||||
| ReflectUtil.newInstance(subClassToLoad, | |||||
| CONSTRUCTOR_ARGS, | |||||
| new Object[] { | |||||
| parent, project, path, | |||||
| Boolean.valueOf(parentFirst) | |||||
| }); | |||||
| } | |||||
| return new AntClassLoader(parent, project, path, parentFirst); | return new AntClassLoader(parent, project, path, parentFirst); | ||||
| } | } | ||||
| @@ -0,0 +1,56 @@ | |||||
| /* | |||||
| * Licensed to the Apache Software Foundation (ASF) under one or more | |||||
| * contributor license agreements. See the NOTICE file distributed with | |||||
| * this work for additional information regarding copyright ownership. | |||||
| * The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
| * (the "License"); you may not use this file except in compliance with | |||||
| * the License. You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.loader; | |||||
| import java.util.Enumeration; | |||||
| import java.io.IOException; | |||||
| import org.apache.tools.ant.AntClassLoader; | |||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.types.Path; | |||||
| /** | |||||
| * Overrides getResources which became non-final in Java5 | |||||
| */ | |||||
| public class AntClassLoader5 extends AntClassLoader { | |||||
| /** | |||||
| * Creates a classloader for the given project using the classpath given. | |||||
| * | |||||
| * @param parent The parent classloader to which unsatisfied loading | |||||
| * attempts are delegated. May be <code>null</code>, | |||||
| * in which case the classloader which loaded this | |||||
| * class is used as the parent. | |||||
| * @param project The project to which this classloader is to belong. | |||||
| * Must not be <code>null</code>. | |||||
| * @param classpath the classpath to use to load the classes. | |||||
| * May be <code>null</code>, in which case no path | |||||
| * elements are set up to start with. | |||||
| * @param parentFirst If <code>true</code>, indicates that the parent | |||||
| * classloader should be consulted before trying to | |||||
| * load the a class through this loader. | |||||
| */ | |||||
| public AntClassLoader5(ClassLoader parent, Project project, | |||||
| Path classpath, boolean parentFirst) { | |||||
| super(parent, project, classpath, parentFirst); | |||||
| } | |||||
| /** {@inheritDoc} */ | |||||
| public Enumeration getResources(String name) throws IOException { | |||||
| return getNamedResources(name); | |||||
| } | |||||
| } | |||||
| @@ -17,6 +17,7 @@ | |||||
| */ | */ | ||||
| package org.apache.tools.ant.util; | package org.apache.tools.ant.util; | ||||
| import java.lang.reflect.Constructor; | |||||
| import java.lang.reflect.InvocationTargetException; | import java.lang.reflect.InvocationTargetException; | ||||
| import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| @@ -35,6 +36,23 @@ public class ReflectUtil { | |||||
| private ReflectUtil() { | private ReflectUtil() { | ||||
| } | } | ||||
| /** | |||||
| * Create an instance of a class using the constructor matching | |||||
| * the given arguments. | |||||
| * @since Ant 1.8.0 | |||||
| */ | |||||
| public static Object newInstance(Class ofClass, | |||||
| Class[] argTypes, | |||||
| Object[] args) { | |||||
| try { | |||||
| Constructor con = ofClass.getConstructor(argTypes); | |||||
| return con.newInstance(args); | |||||
| } catch (Exception t) { | |||||
| throwBuildException(t); | |||||
| return null; // NotReached | |||||
| } | |||||
| } | |||||
| /** | /** | ||||
| * Call a method on the object with no parameters. | * Call a method on the object with no parameters. | ||||
| * @param obj the object to invoke the method on. | * @param obj the object to invoke the method on. | ||||
| @@ -99,12 +99,7 @@ public class AntClassLoaderDelegationTest extends TestCase { | |||||
| } | } | ||||
| private static List enum2List(Enumeration e) { | private static List enum2List(Enumeration e) { | ||||
| // JDK 1.4: return Collections.list(e); | |||||
| List l = new ArrayList(); | |||||
| while (e.hasMoreElements()) { | |||||
| l.add(e.nextElement()); | |||||
| } | |||||
| return l; | |||||
| return Collections.list(e); | |||||
| } | } | ||||
| /** Special loader that just knows how to find TEST_RESOURCE. */ | /** Special loader that just knows how to find TEST_RESOURCE. */ | ||||
| @@ -0,0 +1,65 @@ | |||||
| /* | |||||
| * Licensed to the Apache Software Foundation (ASF) under one or more | |||||
| * contributor license agreements. See the NOTICE file distributed with | |||||
| * this work for additional information regarding copyright ownership. | |||||
| * The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
| * (the "License"); you may not use this file except in compliance with | |||||
| * the License. You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.loader; | |||||
| import java.io.IOException; | |||||
| import java.net.URL; | |||||
| import java.util.Enumeration; | |||||
| import junit.framework.TestCase; | |||||
| import org.apache.tools.ant.AntClassLoader; | |||||
| import org.apache.tools.ant.types.Path; | |||||
| import org.apache.tools.ant.util.CollectionUtils; | |||||
| public class AntClassLoader5Test extends TestCase { | |||||
| /** | |||||
| * Asserts that getResources won't return resources that cannot be | |||||
| * seen by AntClassLoader but by ClassLoader.this.parent. | |||||
| * | |||||
| * @see https://issues.apache.org/bugzilla/show_bug.cgi?id=46752 | |||||
| */ | |||||
| public void testGetResources() throws IOException { | |||||
| AntClassLoader acl = new AntClassLoader5(new EmptyLoader(), null, | |||||
| new Path(null), true); | |||||
| assertNull(acl.getResource("META-INF/MANIFEST.MF")); | |||||
| assertFalse(acl.getResources("META-INF/MANIFEST.MF").hasMoreElements()); | |||||
| // double check using system classloader as parent | |||||
| acl = new AntClassLoader5(null, null, new Path(null), true); | |||||
| assertNotNull(acl.getResource("META-INF/MANIFEST.MF")); | |||||
| assertTrue(acl.getResources("META-INF/MANIFEST.MF").hasMoreElements()); | |||||
| } | |||||
| public void testGetResourcesUsingFactory() throws IOException { | |||||
| AntClassLoader acl = | |||||
| AntClassLoader.newAntClassLoader(new EmptyLoader(), null, | |||||
| new Path(null), true); | |||||
| assertNull(acl.getResource("META-INF/MANIFEST.MF")); | |||||
| assertFalse(acl.getResources("META-INF/MANIFEST.MF").hasMoreElements()); | |||||
| } | |||||
| private static class EmptyLoader extends ClassLoader { | |||||
| public URL getResource(String n) { | |||||
| return null; | |||||
| } | |||||
| public Enumeration getResources(String n) { | |||||
| return new CollectionUtils.EmptyEnumeration(); | |||||
| } | |||||
| } | |||||
| } | |||||