diff --git a/src/etc/testcases/types/poly.xml b/src/etc/testcases/types/poly.xml
new file mode 100644
index 000000000..67ca72008
--- /dev/null
+++ b/src/etc/testcases/types/poly.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/org/apache/tools/ant/IntrospectionHelper.java b/src/main/org/apache/tools/ant/IntrospectionHelper.java
index f4af407fd..362999ae8 100644
--- a/src/main/org/apache/tools/ant/IntrospectionHelper.java
+++ b/src/main/org/apache/tools/ant/IntrospectionHelper.java
@@ -70,10 +70,12 @@ import org.apache.tools.ant.types.Path;
* Helper class that collects the methods a task or nested element
* holds to set attributes, create nested elements or hold PCDATA
* elements.
+ * The class is final as it has a private constructor.
*
* @author Stefan Bodewig
+ * @author Peter Reilly
*/
-public class IntrospectionHelper implements BuildListener {
+public final class IntrospectionHelper implements BuildListener {
/**
* Map from attribute names to attribute types
@@ -205,7 +207,6 @@ public class IntrospectionHelper implements BuildListener {
attributeSetters = new Hashtable();
nestedTypes = new Hashtable();
nestedCreators = new Hashtable();
- nestedStorers = new Hashtable();
addTypeMethods = new ArrayList();
this.bean = bean;
@@ -220,7 +221,7 @@ public class IntrospectionHelper implements BuildListener {
// check of add[Configured](Class) pattern
if (args.length == 1
&& java.lang.Void.TYPE.equals(returnType)
- && (name.equals("add") /*|| name.equals("addConfigured")*/)) {
+ && (name.equals("add") || name.equals("addConfigured"))) {
insertAddTypeMethod(m);
continue;
}
@@ -286,19 +287,31 @@ public class IntrospectionHelper implements BuildListener {
&& args.length == 0) {
String propName = getPropertyName(name, "create");
- nestedTypes.put(propName, returnType);
- nestedCreators.put(propName, new NestedCreator() {
+ // Check if a create of this property is already present
+ // add takes preference over create for CB purposes
+ if (nestedCreators.get(propName) == null) {
+ nestedTypes.put(propName, returnType);
+ nestedCreators.put(propName, new NestedCreator() {
+
+ public boolean isPolyMorphic() {
+ return false;
+ }
+
+ public Class getElementClass() {
+ return null;
+ }
- public Object create(Object parent)
+ public Object create(
+ Project project, Object parent, Object ignore)
throws InvocationTargetException,
IllegalAccessException {
-
return m.invoke(parent, new Object[] {});
}
+ public void store(Object parent, Object child) {
+ }
});
- nestedStorers.remove(propName);
-
+ }
} else if (name.startsWith("addConfigured")
&& java.lang.Void.TYPE.equals(returnType)
&& args.length == 1
@@ -307,24 +320,45 @@ public class IntrospectionHelper implements BuildListener {
&& !args[0].isPrimitive()) {
try {
- final Constructor c =
- args[0].getConstructor(new Class[] {});
+ Constructor constructor = null;
+ try {
+ constructor =
+ args[0].getConstructor(new Class[] {});
+ } catch (NoSuchMethodException ex) {
+ constructor =
+ args[0].getConstructor(new Class[] {
+ Project.class});
+ }
+ final Constructor c = constructor;
String propName = getPropertyName(name, "addConfigured");
nestedTypes.put(propName, args[0]);
nestedCreators.put(propName, new NestedCreator() {
- public Object create(Object parent)
- throws InvocationTargetException, IllegalAccessException, InstantiationException {
+ public boolean isPolyMorphic() {
+ return true;
+ }
- Object o = c.newInstance(new Object[] {});
- return o;
+ public Class getElementClass() {
+ return c.getDeclaringClass();
}
- });
- nestedStorers.put(propName, new NestedStorer() {
+ public Object create(
+ Project project, Object parent, Object child)
+ throws InvocationTargetException,
+ IllegalAccessException, InstantiationException {
+ if (child != null) {
+ return child;
+ } else if (c.getParameterTypes().length == 0) {
+ return c.newInstance(new Object[] {});
+ } else {
+ return c.newInstance(new Object[] {
+ project});
+ }
+ }
public void store(Object parent, Object child)
- throws InvocationTargetException, IllegalAccessException, InstantiationException {
+ throws InvocationTargetException,
+ IllegalAccessException, InstantiationException {
m.invoke(parent, new Object[] {child});
}
@@ -341,22 +375,50 @@ public class IntrospectionHelper implements BuildListener {
&& !args[0].isPrimitive()) {
try {
- final Constructor c =
- args[0].getConstructor(new Class[] {});
+ Constructor constructor = null;
+ try {
+ constructor =
+ args[0].getConstructor(new Class[] {});
+ } catch (NoSuchMethodException ex) {
+ constructor =
+ args[0].getConstructor(new Class[] {
+ Project.class});
+ }
+ final Constructor c = constructor;
String propName = getPropertyName(name, "add");
nestedTypes.put(propName, args[0]);
nestedCreators.put(propName, new NestedCreator() {
- public Object create(Object parent)
- throws InvocationTargetException, IllegalAccessException, InstantiationException {
+ public boolean isPolyMorphic() {
+ return true;
+ }
+
+ public Class getElementClass() {
+ return c.getDeclaringClass();
+ }
+
+ public Object create(
+ Project project, Object parent, Object child)
+ throws InvocationTargetException,
+ IllegalAccessException, InstantiationException {
+ if (child != null) {
+ // ignore
+ } else if (c.getParameterTypes().length == 0) {
+ child = c.newInstance(new Object[] {});
+ } else {
+ child = c.newInstance(new Object[] {
+ project});
+ }
+ m.invoke(parent, new Object[] {child});
+ return child;
+ }
+ public void store(Object parent, Object child)
+ throws InvocationTargetException,
+ IllegalAccessException, InstantiationException {
- Object o = c.newInstance(new Object[] {});
- m.invoke(parent, new Object[] {o});
- return o;
}
});
- nestedStorers.remove(name);
} catch (NoSuchMethodException nse) {
// ignore
}
@@ -535,6 +597,40 @@ public class IntrospectionHelper implements BuildListener {
throw new BuildException(msg);
}
+ private NestedCreator getNestedCreator(Project project, Object parent,
+ String elementName) throws BuildException {
+
+ NestedCreator nc = (NestedCreator) nestedCreators.get(elementName);
+ if (nc == null) {
+ nc = createAddTypeCreator(project, parent, elementName);
+ }
+ if (nc == null && parent instanceof DynamicConfigurator) {
+ DynamicConfigurator dc = (DynamicConfigurator) parent;
+ final Object nestedElement = dc.createDynamicElement(elementName);
+ if (nestedElement != null) {
+ nc = new NestedCreator() {
+ public boolean isPolyMorphic() {
+ return false;
+ }
+ public Class getElementClass() {
+ return null;
+ }
+
+ public Object create(
+ Project project, Object parent, Object ignore) {
+ return nestedElement;
+ }
+ public void store(Object parent, Object child) {
+ }
+ };
+ }
+ }
+ if (nc == null) {
+ throwNotSupported(project, parent, elementName);
+ }
+ return nc;
+ }
+
/**
* Creates a named nested element. Depending on the results of the
* initial introspection, either a method in the given parent instance
@@ -558,32 +654,9 @@ public class IntrospectionHelper implements BuildListener {
*/
public Object createElement(Project project, Object parent,
String elementName) throws BuildException {
- NestedCreator nc = (NestedCreator) nestedCreators.get(elementName);
- if (nc == null && addTypeMethods.size() > 0) {
- Object nestedElement = createAddTypeElement(
- project, parent, elementName);
- if (nestedElement != null) {
- if (project != null) {
- project.setProjectReference(nestedElement);
- }
- return nestedElement;
- }
- }
- if (nc == null && parent instanceof DynamicConfigurator) {
- DynamicConfigurator dc = (DynamicConfigurator) parent;
- Object nestedElement = dc.createDynamicElement(elementName);
- if (nestedElement != null) {
- if (project != null) {
- project.setProjectReference(nestedElement);
- }
- return nestedElement;
- }
- }
- if (nc == null) {
- throwNotSupported(project, parent, elementName);
- }
+ NestedCreator nc = getNestedCreator(project, parent, elementName);
try {
- Object nestedElement = nc.create(parent);
+ Object nestedElement = nc.create(project, parent, null);
if (project != null) {
project.setProjectReference(nestedElement);
}
@@ -603,6 +676,23 @@ public class IntrospectionHelper implements BuildListener {
}
}
+ /**
+ * returns an object that creates and stores an object
+ * for an element of a parent.
+ *
+ * @param project Project to which the parent object belongs.
+ * @param parent Parent object used to create the creator object to
+ * create and store and instance of a subelement.
+ * @param elementName Name of the element to create an instance of.
+ * @return a creator object to create and store the element instance.
+ */
+
+ public Creator getElementCreator(
+ Project project, Object parent, String elementName) {
+ NestedCreator nc = getNestedCreator(project, parent, elementName);
+ return new Creator(project, parent, nc);
+ }
+
/**
* Indicate if this element supports a nested element of the
* given name.
@@ -642,7 +732,7 @@ public class IntrospectionHelper implements BuildListener {
if (elementName == null) {
return;
}
- NestedStorer ns = (NestedStorer) nestedStorers.get(elementName);
+ NestedCreator ns = (NestedCreator) nestedCreators.get(elementName);
if (ns == null) {
return;
}
@@ -876,7 +966,8 @@ public class IntrospectionHelper implements BuildListener {
return new AttributeSetter() {
public void set(Project p, Object parent,
String value)
- throws InvocationTargetException, IllegalAccessException, BuildException {
+ throws InvocationTargetException,
+ IllegalAccessException, BuildException {
try {
Object attribute = c.newInstance(new String[] {value});
if (p != null) {
@@ -934,23 +1025,138 @@ public class IntrospectionHelper implements BuildListener {
}
/**
- * Internal interface used to create nested elements. Not documented
- * in detail for reasons of source code readability.
+ * creator - allows use of create/store external
+ * to IntrospectionHelper.
+ * The class is final as it has a private constructor.
*/
- private interface NestedCreator {
- Object create(Object parent)
- throws InvocationTargetException, IllegalAccessException, InstantiationException;
+ public static final class Creator {
+ private NestedCreator nestedCreator;
+ private Object parent;
+ private Project project;
+ private Object nestedObject;
+ private String polyType;
+
+ /**
+ * Creates a new Creator instance.
+ * This object is given to the UnknownElement to create
+ * objects for sub-elements. UnknownElement calls
+ * create to create an object, the object then gets
+ * configured and then UnknownElement calls store.
+ * SetPolyType may be used to override the type used
+ * to create the object with. SetPolyType gets called
+ * before create.
+ *
+ * @param project the current project
+ * @param parent the parent object to create the object in
+ * @param nestedCreator the nested creator object to use
+ */
+ private Creator(
+ Project project, Object parent, NestedCreator nestedCreator) {
+ this.project = project;
+ this.parent = parent;
+ this.nestedCreator = nestedCreator;
+ }
+
+ /**
+ * Used to override the class used to create the object.
+ *
+ * @param polyType a ant component type name
+ */
+ public void setPolyType(String polyType) {
+ this.polyType = polyType;
+ }
+
+ /**
+ * Create an object using this creator, which is determined
+ * by introspection.
+ *
+ * @return the created object
+ */
+ public Object create() {
+ if (polyType != null) {
+ if (!nestedCreator.isPolyMorphic()) {
+ throw new BuildException(
+ "Not allowed to use the polymorhic form"
+ + " for this element");
+ }
+ Class elementClass = nestedCreator.getElementClass();
+ ComponentHelper helper =
+ ComponentHelper.getComponentHelper(project);
+ nestedObject = ComponentHelper.getComponentHelper(project)
+ .createComponent(polyType);
+ if (nestedObject == null) {
+ throw new BuildException(
+ "Unable to create object of type " + polyType);
+ }
+ }
+ try {
+ nestedObject = nestedCreator.create(
+ project, parent, nestedObject);
+ if (project != null) {
+ project.setProjectReference(nestedObject);
+ }
+ return nestedObject;
+ } catch (IllegalAccessException ex) {
+ throw new BuildException(ex);
+ } catch (InstantiationException ex) {
+ throw new BuildException(ex);
+ } catch (IllegalArgumentException ex) {
+ if (polyType != null) {
+ throw new BuildException(
+ "Invalid type used " + polyType);
+ }
+ throw ex;
+ } catch (InvocationTargetException ex) {
+ Throwable t = ex.getTargetException();
+ if (t instanceof BuildException) {
+ throw (BuildException) t;
+ }
+ throw new BuildException(t);
+ }
+ }
+
+ /**
+ * Stores the nested elemtnt object using a storage method
+ * detimined by introspection.
+ *
+ */
+ public void store() {
+ try {
+ nestedCreator.store(parent, nestedObject);
+ } catch (IllegalAccessException ex) {
+ throw new BuildException(ex);
+ } catch (InstantiationException ex) {
+ throw new BuildException(ex);
+ } catch (IllegalArgumentException ex) {
+ if (polyType != null) {
+ throw new BuildException(
+ "Invalid type used " + polyType);
+ }
+ throw ex;
+ } catch (InvocationTargetException ex) {
+ Throwable t = ex.getTargetException();
+ if (t instanceof BuildException) {
+ throw (BuildException) t;
+ }
+ throw new BuildException(t);
+ }
+ }
}
/**
- * Internal interface used to storing nested elements. Not documented
+ * Internal interface used to create nested elements. Not documented
* in detail for reasons of source code readability.
*/
- private interface NestedStorer {
+ private interface NestedCreator {
+ boolean isPolyMorphic();
+ Class getElementClass();
+ Object create(Project project, Object parent, Object child)
+ throws InvocationTargetException, IllegalAccessException, InstantiationException;
void store(Object parent, Object child)
throws InvocationTargetException, IllegalAccessException, InstantiationException;
}
+
/**
* Internal interface used to setting element attributes. Not documented
* in detail for reasons of source code readability.
@@ -1023,21 +1229,20 @@ public class IntrospectionHelper implements BuildListener {
public void messageLogged(BuildEvent event) {
}
+
/**
- * Check if the parent accepts a typed nested element
- * and if so, create the object, call the parents
- * addmethod.
- * This method is part of the initial support
- * for add(Type) and addConfigured(Type).
- * AddConfigured(Type) will be done later.
+ *
*/
-
- private Object createAddTypeElement(
- Project project, Object parent, String elementName) {
+ private NestedCreator createAddTypeCreator(
+ Project project, Object parent, String elementName)
+ throws BuildException {
+ if (addTypeMethods.size() == 0) {
+ return null;
+ }
ComponentHelper helper = ComponentHelper.getComponentHelper(project);
+
Object addedObject = null;
Method addMethod = null;
-
Class clazz = helper.getComponentClass(elementName);
if (clazz == null) {
return null;
@@ -1050,21 +1255,32 @@ public class IntrospectionHelper implements BuildListener {
if (addedObject == null) {
return null;
}
+ final Method method = addMethod;
+ final Object nestedObject = addedObject;
- try {
- addMethod.invoke(parent, new Object[] {addedObject});
- } catch (IllegalAccessException ex) {
- throw new BuildException(ex);
- } catch (InvocationTargetException ex) {
- Throwable t = ex.getTargetException();
- if (t instanceof BuildException) {
- throw (BuildException) t;
+ return new NestedCreator() {
+ public boolean isPolyMorphic() {
+ return false;
}
- throw new BuildException(t);
- } catch (Throwable t) {
- throw new BuildException(t);
- }
- return addedObject;
+
+ public Class getElementClass() {
+ return null;
+ }
+ public Object create(Project project, Object parent, Object ignore)
+ throws InvocationTargetException, IllegalAccessException {
+ if (!method.getName().endsWith("Configured")) {
+ method.invoke(parent, new Object[]{nestedObject});
+ }
+ return nestedObject;
+ }
+ public void store(Object parent, Object child)
+ throws InvocationTargetException, IllegalAccessException,
+ InstantiationException {
+ if (method.getName().endsWith("Configured")) {
+ method.invoke(parent, new Object[]{nestedObject});
+ }
+ }
+ };
}
/**
diff --git a/src/main/org/apache/tools/ant/RuntimeConfigurable.java b/src/main/org/apache/tools/ant/RuntimeConfigurable.java
index bbaddc8ee..96c9ace9e 100644
--- a/src/main/org/apache/tools/ant/RuntimeConfigurable.java
+++ b/src/main/org/apache/tools/ant/RuntimeConfigurable.java
@@ -77,6 +77,9 @@ import org.xml.sax.helpers.AttributeListImpl;
*/
public class RuntimeConfigurable implements Serializable {
+ /** Polymorphic attribute (May be XML NS attribute later) */
+ private static final String ANT_TYPE = "ant-type";
+
/** Name of the element to configure. */
private String elementTag = null;
@@ -88,7 +91,10 @@ public class RuntimeConfigurable implements Serializable {
*/
private transient Object wrappedObject = null;
- /**
+ /** the creator used to make the wrapped object */
+ private transient IntrospectionHelper.Creator creator;
+
+ /**
* @deprecated
* XML attributes for the element.
*/
@@ -112,6 +118,9 @@ public class RuntimeConfigurable implements Serializable {
/** Indicates if the wrapped object has been configured */
private boolean proxyConfigured = false;
+ /** the polymorphic type */
+ private String polyType = null;
+
/**
* Sole constructor creating a wrapper for the specified object.
*
@@ -139,6 +148,16 @@ public class RuntimeConfigurable implements Serializable {
proxyConfigured = false;
}
+ /**
+ * Sets the creator of the element to be configured
+ * used to store the element in the parent;
+ *
+ * @param creator the creator object
+ */
+ void setCreator(IntrospectionHelper.Creator creator) {
+ this.creator = creator;
+ }
+
/**
* Get the object for which this RuntimeConfigurable holds the configuration
* information
@@ -149,6 +168,13 @@ public class RuntimeConfigurable implements Serializable {
return wrappedObject;
}
+ /**
+ * get the polymorphic type for this element
+ */
+ public String getPolyType() {
+ return polyType;
+ }
+
/**
* Sets the attributes for the wrapped element.
*
@@ -170,12 +196,16 @@ public class RuntimeConfigurable implements Serializable {
* @param value the attribute's value.
*/
public void setAttribute(String name, String value) {
- if (attributeNames == null) {
- attributeNames = new ArrayList();
- attributeMap = new HashMap();
+ if (name.equalsIgnoreCase(ANT_TYPE)) {
+ this.polyType = value;
+ } else {
+ if (attributeNames == null) {
+ attributeNames = new ArrayList();
+ attributeMap = new HashMap();
+ }
+ attributeNames.add(name);
+ attributeMap.put(name, value);
}
- attributeNames.add(name);
- attributeMap.put(name, value);
}
/** Return the attribute map.
@@ -389,6 +419,12 @@ public class RuntimeConfigurable implements Serializable {
childTask.setRuntimeConfigurableWrapper(child);
}
+
+ if ((child.creator != null) && configureChildren) {
+ child.maybeConfigure(p);
+ child.creator.store();
+ continue;
+ }
/*
* backwards compatibility - element names of nested
* elements have been all lower-case in Ant, except for
diff --git a/src/main/org/apache/tools/ant/UnknownElement.java b/src/main/org/apache/tools/ant/UnknownElement.java
index 77010aa01..032d8ef21 100644
--- a/src/main/org/apache/tools/ant/UnknownElement.java
+++ b/src/main/org/apache/tools/ant/UnknownElement.java
@@ -312,17 +312,13 @@ public class UnknownElement extends Task {
Class parentClass = parent.getClass();
IntrospectionHelper ih = IntrospectionHelper.getHelper(parentClass);
+
if (children != null) {
Iterator it = children.iterator();
for (int i = 0; it.hasNext(); i++) {
RuntimeConfigurable childWrapper = parentWrapper.getChild(i);
UnknownElement child = (UnknownElement) it.next();
-
- // backwards compatibility - element names of nested
- // elements have been all lower-case in Ant, except for
- // TaskContainers
- if (!handleChild(ih, parent, child,
- child.getTag().toLowerCase(Locale.US),
+ if (!handleChild(ih, parent, child,
childWrapper)) {
if (!(parent instanceof TaskContainer)) {
ih.throwNotSupported(getProject(), parent,
@@ -475,17 +471,24 @@ public class UnknownElement extends Task {
*/
private boolean handleChild(IntrospectionHelper ih,
Object parent, UnknownElement child,
- String childTag,
RuntimeConfigurable childWrapper) {
- if (ih.supportsNestedElement(childTag)) {
- Object realChild
- = ih.createElement(getProject(), parent, childTag);
+ // backwards compatibility - element names of nested
+ // elements have been all lower-case in Ant, except for
+ // TaskContainers
+ String childName = child.getTag().toLowerCase(Locale.US);
+ if (ih.supportsNestedElement(childName)) {
+ IntrospectionHelper.Creator creator =
+ ih.getElementCreator(getProject(), parent, childName);
+ creator.setPolyType(childWrapper.getPolyType());
+ Object realChild=creator.create();
+ childWrapper.setCreator(creator);
childWrapper.setProxy(realChild);
if (realChild instanceof Task) {
Task childTask = (Task) realChild;
childTask.setRuntimeConfigurableWrapper(childWrapper);
- childTask.setTaskName(childTag);
- childTask.setTaskType(childTag);
+ childTask.setTaskName(childName);
+ childTask.setTaskType(childName);
+ childTask.setLocation(child.getLocation());
}
child.handleChildren(realChild, childWrapper);
return true;
diff --git a/src/testcases/org/apache/tools/ant/types/PolyTest.java b/src/testcases/org/apache/tools/ant/types/PolyTest.java
new file mode 100644
index 000000000..1395080ac
--- /dev/null
+++ b/src/testcases/org/apache/tools/ant/types/PolyTest.java
@@ -0,0 +1,105 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Ant" and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+
+public class PolyTest extends BuildFileTest {
+
+ public PolyTest(String name) {
+ super(name);
+ }
+
+ public void setUp() {
+ configureProject("src/etc/testcases/types/poly.xml");
+ }
+
+ public void testFileSet() {
+ expectLogContaining("fileset", "types.FileSet");
+ }
+
+ public void testFileSetAntType() {
+ expectLogContaining("fileset-ant-type", "types.PolyTest$MyFileSet");
+ }
+
+ public void testPath() {
+ expectLogContaining("path", "types.Path");
+ }
+
+ public void testPathAntType() {
+ expectLogContaining("path-ant-type", "types.PolyTest$MyPath");
+ }
+
+ public static class MyFileSet extends FileSet {}
+
+ public static class MyPath extends Path {
+ public MyPath(Project project) {
+ super(project);
+ }
+ }
+
+ public static class MyTask extends Task {
+ public void addPath(Path path) {
+ log("class of path is " + path.getClass());
+ }
+ public void addFileset(FileSet fileset) {
+ log("class of fileset is " + fileset.getClass());
+ }
+ }
+}