I've been thinking as a result of this bug 
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=18700

I have made a change to the Configuration of UnknownElements so that non-tasks 
types are not configured until their first use. This allows Ant to work 
irrespective of the order in which data types are defined.

For example, given this simple build file (note "testloc" is used before 
definition)

<project name="deferred" default="default">
  <path id="test">
    <pathelement location="${testloc}"/>
  </path>

  <property name="testloc" location="testdir"/>
  <property name="result" refid="test"/>

  <target name="default">
    <echo message="Result is ${result}"/>
  </target>

</project>

Ant 1.5.3 will give 
Result is /home/conor/development/apache/ant-bugs/scratch/${testloc}

whilst with this patch, Ant 1.6 will give
Result is /home/conor/development/apache/ant-bugs/scratch/testdir

which is kind of cool. Far less procedural.

I'm attaching a patch to show the changes but I want to get some feedback if 
this is desirable before committing.

Currently two tests fail (taskname case sensitivity and classfiletest). I 
haven't looked into these failures yet - it may be a problem or something 
I've broken. I don't want to bother until there is consensus that this is 
interesting. 

Thoughts?

Conor

-- 
Conor MacNeill
Blog: http://codefeed.com/blog/
Index: src/main/org/apache/tools/ant/Project.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/Project.java,v
retrieving revision 1.133
diff -3 -u -w -p -r1.133 Project.java
--- src/main/org/apache/tools/ant/Project.java  3 Apr 2003 14:44:01 -0000       
1.133
+++ src/main/org/apache/tools/ant/Project.java  9 Apr 2003 12:06:06 -0000
@@ -2201,13 +2201,16 @@ public class Project {
          */
         public Object get(Object key) {
             //System.out.println("AntRefTable.get " + key);
-            Object o = super.get(key);
-            if (o instanceof UnknownElement) {
+            Object ref = super.get(key);
+            if (ref instanceof UnknownElement) {
                 // Make sure that
-                ((UnknownElement) o).maybeConfigure();
-                o = ((UnknownElement) o).getTask();
+                ((UnknownElement) ref).resolve(false);
+                ref = ((UnknownElement) ref).getTask();
+                if (ref == null) {
+                    ref = super.get(key);
             }
-            return o;
+            }
+            return ref;
         }
     }
 
Index: src/main/org/apache/tools/ant/UnknownElement.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/UnknownElement.java,v
retrieving revision 1.45
diff -3 -u -w -p -r1.45 UnknownElement.java
--- src/main/org/apache/tools/ant/UnknownElement.java   6 Apr 2003 09:30:56 
-0000       1.45
+++ src/main/org/apache/tools/ant/UnknownElement.java   9 Apr 2003 12:06:08 
-0000
@@ -117,22 +117,25 @@ public class UnknownElement extends Task
      * @exception BuildException if the configuration fails
      */
     public void maybeConfigure() throws BuildException {
+        resolve(true);
+    }
+
+    public void resolve(boolean deferDataType) {
         //ProjectComponentHelper 
helper=ProjectComponentHelper.getProjectComponentHelper();
         //realThing = helper.createProjectComponent( this, getProject(), null,
         //                                           this.getTag());
 
+        if (deferDataType) {
+            realThing = makeTask(this, getWrapper());
+            if (realThing == null) {
+                // must be a data type - defer config to first use
+                return;
+            }
+        } else {
         realThing = makeObject(this, getWrapper());
+        }
 
         getWrapper().setProxy(realThing);
-        if (realThing instanceof Task) {
-            Task task = (Task) realThing;
-
-            task.setRuntimeConfigurableWrapper(getWrapper());
-
-            // For Script to work. Ugly
-            // The reference is replaced by RuntimeConfigurable
-            this.getOwningTarget().replaceChild(this, (Task) realThing);
-        }
 
         handleChildren(realThing, getWrapper());
 
@@ -215,10 +218,8 @@ public class UnknownElement extends Task
      */
     public void execute() {
         if (realThing == null) {
-            // plain impossible to get here, maybeConfigure should
-            // have thrown an exception.
-            throw new BuildException("Could not create task of type: "
-                                     + elementName, getLocation());
+            // not a task - so nothing to execute.
+            return;
         }
 
         if (realThing instanceof Task) {
@@ -328,6 +329,11 @@ public class UnknownElement extends Task
             task.setLocation(getLocation());
             // UnknownElement always has an associated target
             task.setOwningTarget(getOwningTarget());
+            task.setRuntimeConfigurableWrapper(getWrapper());
+
+            // For Script to work. Ugly
+            // The reference is replaced by RuntimeConfigurable
+            getOwningTarget().replaceChild(this, task);
             task.init();
         }
         return task;

Reply via email to