Attached is a patch to the IntrospectionHelper to give a little ploymorphic behaviour for nested elements. I haven't committed this as I thought I'd get some reaction first.

Basically what this patch does is the following: When a nested creator cannot be found for a particular nested element, a check is done to see if the element corresponds to a datatype. If it does, a search is done for a superclass of the datatype for which the class does have an addXXX style creator.

In practice, this allows me to use derived types with core tasks without needing to change the core task. For example, if I wanted to use a classfileset type in a <copy> task, I do not need to change copy to add a addClassfileSet() method. I can just use this

<copy todir="deptest">
<classfileset dir="build/classes" baseclass="build/classes/org/apache/tools/ant/Main.class"/>
</copy>



Similarly, I can have classfilesets in jars without changing the <jar> task.


It isn't perfect since some tasks use rolenames in their nested elements

<blah>
    <fromfileset>
    <tofileset>
</blah>

For these tasks, the current method of refids needs to be used. Nevertheless, I think the patch is useful and makes it much more meaningful to define derived types.

The patch as it currently stands is just a proof of concept. There are some inefficiencies which can be factored out if required.

Let me know what you think?

Conor



Index: src/main/org/apache/tools/ant/IntrospectionHelper.java
===================================================================
RCS file: 
/home/cvs/jakarta-ant/src/main/org/apache/tools/ant/IntrospectionHelper.java,v
retrieving revision 1.26
diff -3 -u -w -p -r1.26 IntrospectionHelper.java
--- src/main/org/apache/tools/ant/IntrospectionHelper.java      2001/11/16 
12:05:50     1.26
+++ src/main/org/apache/tools/ant/IntrospectionHelper.java      2001/11/16 
13:19:33
@@ -95,6 +95,11 @@ public class IntrospectionHelper impleme
     private Hashtable nestedCreators;
 
     /**
+     * Holds methods to add nested elements;
+     */
+    private Hashtable nestedAdders;
+    
+    /**
      * Holds methods to store configured nested elements.
      */
     private Hashtable nestedStorers;
@@ -119,6 +124,7 @@ public class IntrospectionHelper impleme
         attributeSetters = new Hashtable();
         nestedTypes = new Hashtable();
         nestedCreators = new Hashtable();
+        nestedAdders = new Hashtable();
         nestedStorers = new Hashtable();
         
         this.bean = bean;
@@ -200,7 +206,7 @@ public class IntrospectionHelper impleme
                         args[0].getConstructor(new Class[] {});
                     String propName = getPropertyName(name, "addConfigured");
                     nestedTypes.put(propName, args[0]);
-                    nestedCreators.put(propName, new NestedCreator() {
+                    nestedAdders.put(propName, new NestedCreator() {
 
                             public Object create(Object parent) 
                                 throws InvocationTargetException, 
IllegalAccessException, InstantiationException {
@@ -233,7 +239,7 @@ public class IntrospectionHelper impleme
                         args[0].getConstructor(new Class[] {});
                     String propName = getPropertyName(name, "add");
                     nestedTypes.put(propName, args[0]);
-                    nestedCreators.put(propName, new NestedCreator() {
+                    nestedAdders.put(propName, new NestedCreator() {
 
                             public Object create(Object parent) 
                                 throws InvocationTargetException, 
IllegalAccessException, InstantiationException {
@@ -314,12 +320,89 @@ public class IntrospectionHelper impleme
     }
 
     /**
+     * This method supports the passing of derived datatypes to addXXX and 
addConfiguredXXX methods.
+     *
+     * It determines if the given element is a defined datatype. It then looks 
for a superclass for
+     * which a creator exists. The creator that does exist must match the type 
name of the superclass
+     */
+    private NestedCreator getPolymorphicTypeCreator(Project project, String 
elementName) {
+        // Is this a type?
+        Hashtable typeDefs = project.getDataTypeDefinitions();
+        if (typeDefs.containsKey(elementName)) {
+            // OK it is a defined type
+            final Class typeClass = (Class)typeDefs.get(elementName);
+            System.out.println("Class name is " + typeClass.getName());
+            Class superClass = typeClass.getSuperclass();
+            while (superClass != null) {
+                // does the super class exist as a type
+                if (typeDefs.contains(superClass)) {
+                    // find out what is the label for this type
+                    String typeDefName = null;
+                    for (Enumeration e = typeDefs.keys(); 
e.hasMoreElements();) {
+                        String label = (String)e.nextElement();
+                        Class typeDef = (Class)typeDefs.get(label);
+                        if (typeDef == superClass) {
+                            typeDefName = label;
+                            break;
+                        }
+                    }
+                    if (typeDefName != null) {
+                        // is there a creator for this 
+                        NestedCreator nc = (NestedCreator) 
nestedAdders.get(typeDefName);
+                        if (nc != null) {
+                            Method[] methods = bean.getMethods();
+                            for (int i=0; i<methods.length; i++) {
+                                final Method m = methods[i];
+                                final String name = m.getName();
+                                String propName = null;
+                                if (name.startsWith("addConfigured")) {
+                                    propName = getPropertyName(name, 
"addConfigured");
+                                }
+                                else if (name.startsWith("add")) {
+                                    propName = getPropertyName(name, "add");
+                                }
+                                if (propName != null && 
propName.equals(typeDefName)) {
+                                    try {
+                                        final Constructor c = 
+                                            typeClass.getConstructor(new 
Class[] {});
+                                        return new NestedCreator() {
+                                            public Object create(Object 
parent) 
+                                                throws 
InvocationTargetException, IllegalAccessException, 
+                                                       InstantiationException {
+                                
+                                                Object o = c.newInstance(new 
Object[] {});
+                                                m.invoke(parent, new Object[] 
{o});
+                                                return o;
+                                            }
+                                        };
+                                    }
+                                    catch (NoSuchMethodException nse) {
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                superClass = superClass.getSuperclass();
+            }
+        }
+        return null;
+    }
+
+    /**
      * Creates a named nested element.
      */
     public Object createElement(Project project, Object element, String 
elementName) 
         throws BuildException {
         NestedCreator nc = (NestedCreator) nestedCreators.get(elementName);
         if (nc == null) {
+            nc = (NestedCreator) nestedAdders.get(elementName);
+        }
+        if (nc == null) {
+            nc = getPolymorphicTypeCreator(project, elementName);
+        }
+        
+        if (nc == null) {
             String msg = getElementName(project, element) +
                 " doesn't support the nested \"" + elementName + "\" element.";
             throw new BuildException(msg);
@@ -652,6 +735,8 @@ public class IntrospectionHelper impleme
         attributeSetters.clear();
         nestedTypes.clear();
         nestedCreators.clear();
+        nestedAdders.clear();
+        nestedStorers.clear();
         addText = null;
         helpers.clear();
     }

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to