diff --git a/WHATSNEW b/WHATSNEW index 490580edb..dc909adc7 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -266,6 +266,10 @@ Fixed bugs: multiple modules have been specified. Bugzilla Report 35301. + * Tasks with a "public void add(SomeType)" method failed to work as + TaskContainers at the same time. + Bugzilla Report 41647. + Other changes: -------------- diff --git a/src/main/org/apache/tools/ant/IntrospectionHelper.java b/src/main/org/apache/tools/ant/IntrospectionHelper.java index 7654a7662..696c6675a 100644 --- a/src/main/org/apache/tools/ant/IntrospectionHelper.java +++ b/src/main/org/apache/tools/ant/IntrospectionHelper.java @@ -518,22 +518,15 @@ public final class IntrospectionHelper { if (nc == null) { nc = createAddTypeCreator(project, parent, elementName); } - if (nc == null && parent instanceof DynamicElementNS) { - DynamicElementNS dc = (DynamicElementNS) parent; + if (nc == null && + (parent instanceof DynamicElementNS + || parent instanceof DynamicElement) + ) { String qName = child == null ? name : child.getQName(); - final Object nestedElement = dc.createDynamicElement( - child == null ? "" : child.getNamespace(), name, qName); - if (nestedElement != null) { - nc = new NestedCreator(null) { - Object create(Project project, Object parent, Object ignore) { - return nestedElement; - } - }; - } - } - if (nc == null && parent instanceof DynamicElement) { - DynamicElement dc = (DynamicElement) parent; - final Object nestedElement = dc.createDynamicElement(name.toLowerCase(Locale.US)); + final Object nestedElement = + createDynamicElement(parent, + child == null ? "" : child.getNamespace(), + name, qName); if (nestedElement != null) { nc = new NestedCreator(null) { Object create(Project project, Object parent, Object ignore) { @@ -548,6 +541,27 @@ public final class IntrospectionHelper { return nc; } + /** + * Invokes the "correct" createDynamicElement method on parent in + * order to obtain a child element by name. + * + * @since Ant 1.8.0. + */ + private Object createDynamicElement(Object parent, String ns, + String localName, String qName) { + Object nestedElement = null; + if (parent instanceof DynamicElementNS) { + DynamicElementNS dc = (DynamicElementNS) parent; + nestedElement = dc.createDynamicElement(ns, localName, qName); + } + if (nestedElement == null && parent instanceof DynamicElement) { + DynamicElement dc = (DynamicElement) parent; + nestedElement = + dc.createDynamicElement(localName.toLowerCase(Locale.US)); + } + return nestedElement; + } + /** * Creates a named nested element. Depending on the results of the * initial introspection, either a method in the given parent instance @@ -654,6 +668,12 @@ public final class IntrospectionHelper { * Indicate if this element supports a nested element of the * given name. * + *
Note that this method will always return true if the + * introspected class is {@link #isDynamic dynamic} or contains a + * method named "add" with void return type and a single argument. + * To ge a more thorough answer, use the four-arg version of this + * method instead.
+ * * @param parentUri the uri of the parent * @param elementName the name of the nested element being checked * @@ -666,6 +686,48 @@ public final class IntrospectionHelper { return supportsReflectElement(parentUri, elementName); } + /** + * Indicate if this element supports a nested element of the + * given name. + * + * @param parentUri the uri of the parent + * @param elementName the name of the nested element being checked + * @param project currently executing project instance + * @param parent the parent element (an instance of the introspected class) + * @param childQName QName of the child element, may be null + * + * @return true if the given nested element is supported + * @since Ant 1.8.0. + */ + public boolean supportsNestedElement(String parentUri, String elementName, + Project project, Object parent, + String childQName) { + if (addTypeMethods.size() > 0 + && createAddTypeCreator(project, parent, elementName) != null) { + return true; + } + if (isDynamic()) { + /* + breaks several tests, in particular EchoXML because it + creates additional empty child elements in XMLFragment + + String localName = + ProjectHelper.extractNameFromComponentName(elementName); + String uri = ProjectHelper.extractUriFromComponentName(elementName); + if (uri.equals(ProjectHelper.ANT_CORE_URI)) { + uri = ""; + } + if (createDynamicElement(parent, uri, localName, + childQName == null ? localName : childQName) + != null) { + return true; + } + */ + return true; + } + return supportsReflectElement(parentUri, elementName); + } + /** * Check if this element supports a nested element from reflection. * diff --git a/src/main/org/apache/tools/ant/UnknownElement.java b/src/main/org/apache/tools/ant/UnknownElement.java index 10d0ca3f8..e78b5ac1a 100644 --- a/src/main/org/apache/tools/ant/UnknownElement.java +++ b/src/main/org/apache/tools/ant/UnknownElement.java @@ -542,7 +542,8 @@ public class UnknownElement extends Task { RuntimeConfigurable childWrapper) { String childName = ProjectHelper.genComponentName( child.getNamespace(), child.getTag()); - if (ih.supportsNestedElement(parentUri, childName)) { + if (ih.supportsNestedElement(parentUri, childName, + getProject(), parent, child.getQName())) { IntrospectionHelper.Creator creator = ih.getElementCreator( getProject(), parentUri, parent, childName, child); diff --git a/src/tests/antunit/core/nested-elements-test.xml b/src/tests/antunit/core/nested-elements-test.xml new file mode 100644 index 000000000..955b8ba6e --- /dev/null +++ b/src/tests/antunit/core/nested-elements-test.xml @@ -0,0 +1,54 @@ + + +