Index: src/main/org/apache/tools/ant/IntrospectionHelper.java =================================================================== --- src/main/org/apache/tools/ant/IntrospectionHelper.java (revision 426873) +++ src/main/org/apache/tools/ant/IntrospectionHelper.java (working copy) @@ -279,6 +279,79 @@ } /** + * Returns a list containing the (US lowercased) names of the + * attributes for which property expansion should not take place. + * + *

The attribute names are extracted from the name of the Methods + * returned by the invocation of the bean's method + * public java.lang.reflect.Method [] + * getUnexpandedAttrSetters(), if defined. + * The methods must start with set.

+ * + *

Ex.: (supposing the caller of this method is RuntimeConfigurable) + * if an element has method setMyAttr(String str) + * and a method getUnexpandedAttrSetters() returning an array + * containing the method setUnexAttr and for an element + * you define the attribute unexattr="${path.separator}", + * the method's str parameter will contain the unexpanded string, + * that is "${path.separator}" instead of ":".

+ * + * @param bean The element. Must not be null. + * @return The list of attribute names for which + * property expansion shouldn't take place, + * or null if the bean + * doesn't define the list of corresponding methods + * or the list is empty. + */ + protected List unexpandedAttributes(Object bean) { + + Method m = null; + try { + m = bean.getClass().getMethod("getUnexpandedAttrSetters",null); + } catch (NoSuchMethodException nsme) { + return null; + } + + Class returnType = m.getReturnType(); + + if ((returnType.getComponentType() != null) + && Method.class.isAssignableFrom( + returnType.getComponentType())) { + // it's the right method + Object result = null; + try { + result = m.invoke(bean, new Object[] {}); + } catch (InvocationTargetException ite) { + } catch (IllegalAccessException iae) { + } + if (result != null) { + Method [] ma = (Method []) result; + if (ma.length > 0) { + List names = null; + int curM = 0; + while (curM < ma.length) { + if (ma[curM] != null) { + String mname = ma[curM].getName(); + if (mname.startsWith("set")) { + String aname = getPropertyName( + mname,"set"); + if (names == null) { + names = new ArrayList(); + } + names.add(aname); + } + } + curM++; + } + return names; + } + } + } + + return null; + } + + /** * Certain set methods are part of the Ant core interface to tasks and * therefore not to be considered for introspection * Index: src/main/org/apache/tools/ant/RuntimeConfigurable.java =================================================================== --- src/main/org/apache/tools/ant/RuntimeConfigurable.java (revision 426873) +++ src/main/org/apache/tools/ant/RuntimeConfigurable.java (working copy) @@ -357,13 +357,18 @@ IntrospectionHelper ih = IntrospectionHelper.getHelper(p, target.getClass()); + List unexpandedAttrs = ih.unexpandedAttributes(target); + if (attributeNames != null) { for (int i = 0; i < attributeNames.size(); i++) { String name = (String) attributeNames.get(i); String value = (String) attributeMap.get(name); // reflect these into the target - value = p.replaceProperties(value); + if ((unexpandedAttrs == null) || !unexpandedAttrs.contains( + name.toLowerCase(Locale.US))) { + value = p.replaceProperties(value); + } try { ih.setAttribute(p, target, name, value); } catch (UnsupportedAttributeException be) { Index: src/main/org/apache/tools/ant/ProjectHelper.java =================================================================== --- src/main/org/apache/tools/ant/ProjectHelper.java (revision 426873) +++ src/main/org/apache/tools/ant/ProjectHelper.java (working copy) @@ -22,6 +22,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.Hashtable; +import java.util.List; import java.util.Locale; import java.util.Vector; import org.apache.tools.ant.helper.ProjectHelper2; @@ -307,13 +308,18 @@ IntrospectionHelper ih = IntrospectionHelper.getHelper(project, target.getClass()); + List unexpandedAttrs = ih.unexpandedAttributes(target); + for (int i = 0; i < attrs.getLength(); i++) { // reflect these into the target - String value = replaceProperties(project, attrs.getValue(i), - project.getProperties()); + String name = attrs.getName(i).toLowerCase(Locale.US); + String value = attrs.getValue(i); + if ((unexpandedAttrs == null) + || !unexpandedAttrs.contains(name)) { + value = project.replaceProperties(value); + } try { - ih.setAttribute(project, target, - attrs.getName(i).toLowerCase(Locale.US), value); + ih.setAttribute(project, target, name, value); } catch (BuildException be) { // id attribute must be set externally Index: src/etc/testcases/core/customtasks.xml =================================================================== --- src/etc/testcases/core/customtasks.xml (revision 0) +++ src/etc/testcases/core/customtasks.xml (revision 0) @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + Index: src/testcases/org/apache/tools/ant/CustomTasksTest.java =================================================================== --- src/testcases/org/apache/tools/ant/CustomTasksTest.java (revision 0) +++ src/testcases/org/apache/tools/ant/CustomTasksTest.java (revision 0) @@ -0,0 +1,78 @@ +/* + * Copyright 2006 The Apache Software Foundation + * + * Licensed 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; + +import org.apache.tools.ant.BuildFileTest; +import java.lang.reflect.Method; + +/** + * + */ +public class CustomTasksTest extends BuildFileTest { + + public CustomTasksTest(String name) { + super(name); + } + + public void setUp() { + configureProject("src/etc/testcases/core/customtasks.xml"); + } + + public static class NotExpandedATask extends Task { + private String expString = null; + private String unexpString = null; + private String prefix = null; + + public void setExpString(String expString) { + this.expString = expString; + } + + public void setUnexpString(String unexpString) { + this.unexpString = unexpString; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public Method [] getUnexpandedAttrSetters() { + Method method = null; + try { + method = getClass().getMethod("setUnexpString", + new Class[] {String.class}); + } catch (NoSuchMethodException nsme) { + throw new BuildException(nsme); + } + return new Method[] {method}; + } + + public void execute() throws BuildException { + if ((prefix == null) || (expString == null) || (unexpString == null)) { + throw new BuildException("Bad test initialisation"); + } + getProject().setNewProperty(prefix + ".exp", expString); + getProject().setNewProperty(prefix + ".unexp", unexpString); + } + } + /** + */ + public void testUnexpandedAttr() { + executeTarget("unexpandedattr"); + } +} +