|
@@ -1,7 +1,7 @@ |
|
|
/* |
|
|
/* |
|
|
* The Apache Software License, Version 1.1 |
|
|
* The Apache Software License, Version 1.1 |
|
|
* |
|
|
* |
|
|
* Copyright (c) 2000-2001 The Apache Software Foundation. All rights |
|
|
|
|
|
|
|
|
* Copyright (c) 2000-2003 The Apache Software Foundation. All rights |
|
|
* reserved. |
|
|
* reserved. |
|
|
* |
|
|
* |
|
|
* Redistribution and use in source and binary forms, with or without |
|
|
* Redistribution and use in source and binary forms, with or without |
|
@@ -23,7 +23,7 @@ |
|
|
* Alternately, this acknowlegement may appear in the software itself, |
|
|
* Alternately, this acknowlegement may appear in the software itself, |
|
|
* if and wherever such third-party acknowlegements normally appear. |
|
|
* if and wherever such third-party acknowlegements normally appear. |
|
|
* |
|
|
* |
|
|
* 4. The names "The Jakarta Project", "Ant", and "Apache Software |
|
|
|
|
|
|
|
|
* 4. The names "Ant" and "Apache Software |
|
|
* Foundation" must not be used to endorse or promote products derived |
|
|
* Foundation" must not be used to endorse or promote products derived |
|
|
* from this software without prior written permission. For written |
|
|
* from this software without prior written permission. For written |
|
|
* permission, please contact apache@apache.org. |
|
|
* permission, please contact apache@apache.org. |
|
@@ -54,16 +54,15 @@ |
|
|
|
|
|
|
|
|
package org.apache.tools.ant; |
|
|
package org.apache.tools.ant; |
|
|
|
|
|
|
|
|
import org.apache.tools.ant.types.Path; |
|
|
|
|
|
import org.apache.tools.ant.types.EnumeratedAttribute; |
|
|
|
|
|
|
|
|
|
|
|
import java.lang.reflect.Method; |
|
|
|
|
|
import java.lang.reflect.InvocationTargetException; |
|
|
|
|
|
import java.lang.reflect.Constructor; |
|
|
|
|
|
import java.io.File; |
|
|
import java.io.File; |
|
|
|
|
|
import java.lang.reflect.Constructor; |
|
|
|
|
|
import java.lang.reflect.InvocationTargetException; |
|
|
|
|
|
import java.lang.reflect.Method; |
|
|
import java.util.Enumeration; |
|
|
import java.util.Enumeration; |
|
|
import java.util.Hashtable; |
|
|
import java.util.Hashtable; |
|
|
import java.util.Locale; |
|
|
import java.util.Locale; |
|
|
|
|
|
import org.apache.tools.ant.types.EnumeratedAttribute; |
|
|
|
|
|
import org.apache.tools.ant.types.Path; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Helper class that collects the methods a task or nested element |
|
|
* Helper class that collects the methods a task or nested element |
|
@@ -75,45 +74,125 @@ import java.util.Locale; |
|
|
public class IntrospectionHelper implements BuildListener { |
|
|
public class IntrospectionHelper implements BuildListener { |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* holds the types of the attributes that could be set. |
|
|
|
|
|
|
|
|
* Map from attribute names to attribute types |
|
|
|
|
|
* (String to Class). |
|
|
*/ |
|
|
*/ |
|
|
private Hashtable attributeTypes; |
|
|
private Hashtable attributeTypes; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* holds the attribute setter methods. |
|
|
|
|
|
|
|
|
* Map from attribute names to attribute setter methods |
|
|
|
|
|
* (String to AttributeSetter). |
|
|
*/ |
|
|
*/ |
|
|
private Hashtable attributeSetters; |
|
|
private Hashtable attributeSetters; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Holds the types of nested elements that could be created. |
|
|
|
|
|
|
|
|
* Map from attribute names to nested types |
|
|
|
|
|
* (String to Class). |
|
|
*/ |
|
|
*/ |
|
|
private Hashtable nestedTypes; |
|
|
private Hashtable nestedTypes; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Holds methods to create nested elements. |
|
|
|
|
|
|
|
|
* Map from attribute names to methods to create nested types |
|
|
|
|
|
* (String to NestedCreator). |
|
|
*/ |
|
|
*/ |
|
|
private Hashtable nestedCreators; |
|
|
private Hashtable nestedCreators; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Holds methods to store configured nested elements. |
|
|
|
|
|
|
|
|
* Map from attribute names to methods to store configured nested types |
|
|
|
|
|
* (String to NestedStorer). |
|
|
*/ |
|
|
*/ |
|
|
private Hashtable nestedStorers; |
|
|
private Hashtable nestedStorers; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* The method to add PCDATA stuff. |
|
|
|
|
|
|
|
|
* The method to invoke to add PCDATA. |
|
|
*/ |
|
|
*/ |
|
|
private Method addText = null; |
|
|
private Method addText = null; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* The Class that's been introspected. |
|
|
|
|
|
|
|
|
* The class introspected by this instance. |
|
|
*/ |
|
|
*/ |
|
|
private Class bean; |
|
|
private Class bean; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* instances we've already created |
|
|
|
|
|
|
|
|
* Helper instances we've already created (Class to IntrospectionHelper). |
|
|
*/ |
|
|
*/ |
|
|
private static Hashtable helpers = new Hashtable(); |
|
|
private static Hashtable helpers = new Hashtable(); |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Map from primitive types to wrapper classes for use in |
|
|
|
|
|
* createAttributeSetter (Class to Class). Note that char |
|
|
|
|
|
* and boolean are in here even though they get special treatment |
|
|
|
|
|
* - this way we only need to test for the wrapper class. |
|
|
|
|
|
*/ |
|
|
|
|
|
private static final Hashtable PRIMITIVE_TYPE_MAP = new Hashtable(8); |
|
|
|
|
|
|
|
|
|
|
|
// Set up PRIMITIVE_TYPE_MAP |
|
|
|
|
|
static { |
|
|
|
|
|
Class[] primitives = {Boolean.TYPE, Byte.TYPE, Character.TYPE, |
|
|
|
|
|
Short.TYPE, Integer.TYPE, Long.TYPE, |
|
|
|
|
|
Float.TYPE, Double.TYPE}; |
|
|
|
|
|
Class[] wrappers = {Boolean.class, Byte.class, Character.class, |
|
|
|
|
|
Short.class, Integer.class, Long.class, |
|
|
|
|
|
Float.class, Double.class}; |
|
|
|
|
|
for (int i = 0; i < primitives.length; i++) { |
|
|
|
|
|
PRIMITIVE_TYPE_MAP.put (primitives[i], wrappers[i]); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// XXX: (Jon Skeet) The documentation below doesn't draw a clear |
|
|
|
|
|
// distinction between addConfigured and add. It's obvious what the |
|
|
|
|
|
// code *here* does (addConfigured sets both a creator method which |
|
|
|
|
|
// calls a no-arg constructor and a storer method which calls the |
|
|
|
|
|
// method we're looking at, whlie add just sets a creator method |
|
|
|
|
|
// which calls the method we're looking at) but it's not at all |
|
|
|
|
|
// obvious what the difference in actual *effect* will be later |
|
|
|
|
|
// on. I can't see any mention of addConfiguredXXX in "Developing |
|
|
|
|
|
// with Ant" (at least in the version on the web site). Someone |
|
|
|
|
|
// who understands should update this documentation |
|
|
|
|
|
// (and preferably the manual too) at some stage. |
|
|
|
|
|
/** |
|
|
|
|
|
* Sole constructor, which is private to ensure that all |
|
|
|
|
|
* IntrospectionHelpers are created via {@link #getHelper(Class) getHelper}. |
|
|
|
|
|
* Introspects the given class for bean-like methods. |
|
|
|
|
|
* Each method is examined in turn, and the following rules are applied: |
|
|
|
|
|
* <p> |
|
|
|
|
|
* <ul> |
|
|
|
|
|
* <li>If the method is <code>Task.setLocation(Location)</code>, |
|
|
|
|
|
* <code>Task.setTaskType(String)</code> |
|
|
|
|
|
* or <code>TaskContainer.addTask(Task)</code>, it is ignored. These |
|
|
|
|
|
* methods are handled differently elsewhere. |
|
|
|
|
|
* <li><code>void addText(String)</code> is recognised as the method for |
|
|
|
|
|
* adding PCDATA to a bean. |
|
|
|
|
|
* <li><code>void setFoo(Bar)</code> is recognised as a method for |
|
|
|
|
|
* setting the value of attribute <code>foo</code>, so long as |
|
|
|
|
|
* <code>Bar</code> is non-void and is not an array type. Non-String |
|
|
|
|
|
* parameter types always overload String parameter types, but that is |
|
|
|
|
|
* the only guarantee made in terms of priority. |
|
|
|
|
|
* <li><code>Foo createBar()</code> is recognised as a method for |
|
|
|
|
|
* creating a nested element called <code>bar</code> of type |
|
|
|
|
|
* <code>Foo</code>, so long as <code>Foo</code> is not a primitive or |
|
|
|
|
|
* array type. |
|
|
|
|
|
* <li><code>void addConfiguredFoo(Bar)</code> is recognised as a |
|
|
|
|
|
* method for storing a pre-configured element called |
|
|
|
|
|
* <code>foo</code> and of type <code>Bar</code>, so long as |
|
|
|
|
|
* <code>Bar</code> is not an array, primitive or String type. |
|
|
|
|
|
* <code>Bar</code> must have an accessible constructor taking no |
|
|
|
|
|
* arguments. |
|
|
|
|
|
* <li><code>void addFoo(Bar)</code> is recognised as a |
|
|
|
|
|
* method for storing an element called <code>foobar</code> |
|
|
|
|
|
* and of type <code>Baz</code>, so long as |
|
|
|
|
|
* <code>Baz</code> is not an array, primitive or String type. |
|
|
|
|
|
* <code>Baz</code> must have an accessible constructor taking no |
|
|
|
|
|
* arguments. |
|
|
|
|
|
* </ul> |
|
|
|
|
|
* Note that only one method is retained to create/set/addConfigured/add |
|
|
|
|
|
* any element or attribute. |
|
|
|
|
|
* |
|
|
|
|
|
* @param bean The bean type to introspect. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @see #getHelper(Class) |
|
|
|
|
|
*/ |
|
|
private IntrospectionHelper(final Class bean) { |
|
|
private IntrospectionHelper(final Class bean) { |
|
|
attributeTypes = new Hashtable(); |
|
|
attributeTypes = new Hashtable(); |
|
|
attributeSetters = new Hashtable(); |
|
|
attributeSetters = new Hashtable(); |
|
@@ -124,7 +203,7 @@ public class IntrospectionHelper implements BuildListener { |
|
|
this.bean = bean; |
|
|
this.bean = bean; |
|
|
|
|
|
|
|
|
Method[] methods = bean.getMethods(); |
|
|
Method[] methods = bean.getMethods(); |
|
|
for (int i=0; i<methods.length; i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < methods.length; i++) { |
|
|
final Method m = methods[i]; |
|
|
final Method m = methods[i]; |
|
|
final String name = m.getName(); |
|
|
final String name = m.getName(); |
|
|
Class returnType = m.getReturnType(); |
|
|
Class returnType = m.getReturnType(); |
|
@@ -132,23 +211,16 @@ public class IntrospectionHelper implements BuildListener { |
|
|
|
|
|
|
|
|
// not really user settable properties on tasks |
|
|
// not really user settable properties on tasks |
|
|
if (org.apache.tools.ant.Task.class.isAssignableFrom(bean) |
|
|
if (org.apache.tools.ant.Task.class.isAssignableFrom(bean) |
|
|
&& args.length == 1 && |
|
|
|
|
|
( |
|
|
|
|
|
( |
|
|
|
|
|
"setLocation".equals(name) && org.apache.tools.ant.Location.class.equals(args[0]) |
|
|
|
|
|
) || ( |
|
|
|
|
|
"setTaskType".equals(name) && java.lang.String.class.equals(args[0]) |
|
|
|
|
|
) |
|
|
|
|
|
)) { |
|
|
|
|
|
|
|
|
&& args.length == 1 && isHiddenSetMethod(name, args[0])) { |
|
|
continue; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// hide addTask for TaskContainers |
|
|
// hide addTask for TaskContainers |
|
|
// if (org.apache.tools.ant.TaskContainer.class.isAssignableFrom(bean) |
|
|
|
|
|
// && args.length == 1 && "addTask".equals(name) |
|
|
|
|
|
// && org.apache.tools.ant.Task.class.equals(args[0])) { |
|
|
|
|
|
// continue; |
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
if (org.apache.tools.ant.TaskContainer.class.isAssignableFrom(bean) |
|
|
|
|
|
&& args.length == 1 && "addTask".equals(name) |
|
|
|
|
|
&& org.apache.tools.ant.Task.class.equals(args[0])) { |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ("addText".equals(name) |
|
|
if ("addText".equals(name) |
|
@@ -185,7 +257,7 @@ public class IntrospectionHelper implements BuildListener { |
|
|
particular order. |
|
|
particular order. |
|
|
*/ |
|
|
*/ |
|
|
} |
|
|
} |
|
|
AttributeSetter as = createAttributeSetter(m, args[0]); |
|
|
|
|
|
|
|
|
AttributeSetter as = createAttributeSetter(m, args[0], propName); |
|
|
if (as != null) { |
|
|
if (as != null) { |
|
|
attributeTypes.put(propName, args[0]); |
|
|
attributeTypes.put(propName, args[0]); |
|
|
attributeSetters.put(propName, as); |
|
|
attributeSetters.put(propName, as); |
|
@@ -225,9 +297,7 @@ public class IntrospectionHelper implements BuildListener { |
|
|
nestedCreators.put(propName, new NestedCreator() { |
|
|
nestedCreators.put(propName, new NestedCreator() { |
|
|
|
|
|
|
|
|
public Object create(Object parent) |
|
|
public Object create(Object parent) |
|
|
throws InvocationTargetException, |
|
|
|
|
|
IllegalAccessException, |
|
|
|
|
|
InstantiationException { |
|
|
|
|
|
|
|
|
throws InvocationTargetException, IllegalAccessException, InstantiationException { |
|
|
|
|
|
|
|
|
Object o = c.newInstance(new Object[] {}); |
|
|
Object o = c.newInstance(new Object[] {}); |
|
|
return o; |
|
|
return o; |
|
@@ -237,9 +307,7 @@ public class IntrospectionHelper implements BuildListener { |
|
|
nestedStorers.put(propName, new NestedStorer() { |
|
|
nestedStorers.put(propName, new NestedStorer() { |
|
|
|
|
|
|
|
|
public void store(Object parent, Object child) |
|
|
public void store(Object parent, Object child) |
|
|
throws InvocationTargetException, |
|
|
|
|
|
IllegalAccessException, |
|
|
|
|
|
InstantiationException { |
|
|
|
|
|
|
|
|
throws InvocationTargetException, IllegalAccessException, InstantiationException { |
|
|
|
|
|
|
|
|
m.invoke(parent, new Object[] {child}); |
|
|
m.invoke(parent, new Object[] {child}); |
|
|
} |
|
|
} |
|
@@ -262,9 +330,7 @@ public class IntrospectionHelper implements BuildListener { |
|
|
nestedCreators.put(propName, new NestedCreator() { |
|
|
nestedCreators.put(propName, new NestedCreator() { |
|
|
|
|
|
|
|
|
public Object create(Object parent) |
|
|
public Object create(Object parent) |
|
|
throws InvocationTargetException, |
|
|
|
|
|
IllegalAccessException, |
|
|
|
|
|
InstantiationException { |
|
|
|
|
|
|
|
|
throws InvocationTargetException, IllegalAccessException, InstantiationException { |
|
|
|
|
|
|
|
|
Object o = c.newInstance(new Object[] {}); |
|
|
Object o = c.newInstance(new Object[] {}); |
|
|
m.invoke(parent, new Object[] {o}); |
|
|
m.invoke(parent, new Object[] {o}); |
|
@@ -279,8 +345,36 @@ public class IntrospectionHelper implements BuildListener { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Certain set methods are part of the Ant core interface to tasks and |
|
|
|
|
|
* therefore not to be considered for introspection |
|
|
|
|
|
* |
|
|
|
|
|
* @param name the name of the set method |
|
|
|
|
|
* @param type the type of the set method's parameter |
|
|
|
|
|
* @return true if the given set method is to be hidden. |
|
|
|
|
|
*/ |
|
|
|
|
|
private boolean isHiddenSetMethod(String name, Class type) { |
|
|
|
|
|
if ("setLocation".equals(name) |
|
|
|
|
|
&& org.apache.tools.ant.Location.class.equals(type)) { |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ("setTaskType".equals(name) |
|
|
|
|
|
&& java.lang.String.class.equals(type)) { |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Factory method for helper objects. |
|
|
|
|
|
|
|
|
* Returns a helper for the given class, either from the cache |
|
|
|
|
|
* or by creating a new instance. |
|
|
|
|
|
* |
|
|
|
|
|
* @param c The class for which a helper is required. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @return a helper for the specified class |
|
|
*/ |
|
|
*/ |
|
|
public static synchronized IntrospectionHelper getHelper(Class c) { |
|
|
public static synchronized IntrospectionHelper getHelper(Class c) { |
|
|
IntrospectionHelper ih = (IntrospectionHelper) helpers.get(c); |
|
|
IntrospectionHelper ih = (IntrospectionHelper) helpers.get(c); |
|
@@ -292,17 +386,63 @@ public class IntrospectionHelper implements BuildListener { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Sets the named attribute. |
|
|
|
|
|
|
|
|
* Returns a helper for the given class, either from the cache |
|
|
|
|
|
* or by creating a new instance. |
|
|
|
|
|
* |
|
|
|
|
|
* The method will make sure the helper will be cleaned up at the end of |
|
|
|
|
|
* the project, and only one instance will be created for each class. |
|
|
|
|
|
* |
|
|
|
|
|
* @param c The class for which a helper is required. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @return a helper for the specified class |
|
|
|
|
|
*/ |
|
|
|
|
|
public static synchronized IntrospectionHelper getHelper(Project p, Class c) |
|
|
|
|
|
{ |
|
|
|
|
|
IntrospectionHelper ih = (IntrospectionHelper) helpers.get(c); |
|
|
|
|
|
if (ih == null) { |
|
|
|
|
|
ih = new IntrospectionHelper(c); |
|
|
|
|
|
helpers.put(c, ih); |
|
|
|
|
|
// Cleanup at end of project |
|
|
|
|
|
p.addBuildListener(ih); |
|
|
|
|
|
} |
|
|
|
|
|
return ih; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Sets the named attribute in the given element, which is part of the |
|
|
|
|
|
* given project. |
|
|
|
|
|
* |
|
|
|
|
|
* @param p The project containing the element. This is used when files |
|
|
|
|
|
* need to be resolved. Must not be <code>null</code>. |
|
|
|
|
|
* @param element The element to set the attribute in. Must not be |
|
|
|
|
|
* <code>null</code>. |
|
|
|
|
|
* @param attributeName The name of the attribute to set. Must not be |
|
|
|
|
|
* <code>null</code>. |
|
|
|
|
|
* @param value The value to set the attribute to. This may be interpreted |
|
|
|
|
|
* or converted to the necessary type if the setter method |
|
|
|
|
|
* doesn't just take a string. Must not be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @exception BuildException if the introspected class doesn't support |
|
|
|
|
|
* the given attribute, or if the setting |
|
|
|
|
|
* method fails. |
|
|
*/ |
|
|
*/ |
|
|
public void setAttribute(Project p, Object element, String attributeName, |
|
|
public void setAttribute(Project p, Object element, String attributeName, |
|
|
String value) |
|
|
|
|
|
throws BuildException { |
|
|
|
|
|
AttributeSetter as = (AttributeSetter) attributeSetters.get(attributeName); |
|
|
|
|
|
|
|
|
String value) throws BuildException { |
|
|
|
|
|
AttributeSetter as |
|
|
|
|
|
= (AttributeSetter) attributeSetters.get(attributeName); |
|
|
if (as == null) { |
|
|
if (as == null) { |
|
|
String msg = getElementName(p, element) + |
|
|
|
|
|
//String msg = "Class " + element.getClass().getName() + |
|
|
|
|
|
" doesn't support the \"" + attributeName + "\" attribute."; |
|
|
|
|
|
throw new BuildException(msg); |
|
|
|
|
|
|
|
|
if (element instanceof DynamicConfigurator) { |
|
|
|
|
|
DynamicConfigurator dc = (DynamicConfigurator) element; |
|
|
|
|
|
dc.setDynamicAttribute(attributeName, value); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
String msg = getElementName(p, element) + |
|
|
|
|
|
" doesn't support the \"" + attributeName + |
|
|
|
|
|
"\" attribute."; |
|
|
|
|
|
throw new BuildException(msg); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
try { |
|
|
try { |
|
|
as.set(p, element, value); |
|
|
as.set(p, element, value); |
|
@@ -319,18 +459,32 @@ public class IntrospectionHelper implements BuildListener { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Adds PCDATA areas. |
|
|
|
|
|
|
|
|
* Adds PCDATA to an element, using the element's |
|
|
|
|
|
* <code>void addText(String)</code> method, if it has one. If no |
|
|
|
|
|
* such method is present, a BuildException is thrown if the |
|
|
|
|
|
* given text contains non-whitespace. |
|
|
|
|
|
* |
|
|
|
|
|
* @param project The project which the element is part of. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* @param element The element to add the text to. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* @param text The text to add. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @exception BuildException if non-whitespace text is provided and no |
|
|
|
|
|
* method is available to handle it, or if |
|
|
|
|
|
* the handling method fails. |
|
|
*/ |
|
|
*/ |
|
|
public void addText(Project project, Object element, String text) { |
|
|
|
|
|
|
|
|
public void addText(Project project, Object element, String text) |
|
|
|
|
|
throws BuildException { |
|
|
if (addText == null) { |
|
|
if (addText == null) { |
|
|
// Element doesn't handle text content |
|
|
// Element doesn't handle text content |
|
|
if ( text.trim().length() == 0 ) { |
|
|
|
|
|
|
|
|
if (text.trim().length() == 0) { |
|
|
// Only whitespace - ignore |
|
|
// Only whitespace - ignore |
|
|
return; |
|
|
return; |
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
|
|
|
} else { |
|
|
// Not whitespace - fail |
|
|
// Not whitespace - fail |
|
|
String msg = getElementName(project, element) + |
|
|
|
|
|
|
|
|
String msg = project.getElementName(element) + |
|
|
" doesn't support nested text data."; |
|
|
" doesn't support nested text data."; |
|
|
throw new BuildException(msg); |
|
|
throw new BuildException(msg); |
|
|
} |
|
|
} |
|
@@ -350,25 +504,46 @@ public class IntrospectionHelper implements BuildListener { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Creates a named nested element. |
|
|
|
|
|
|
|
|
* Creates a named nested element. Depending on the results of the |
|
|
|
|
|
* initial introspection, either a method in the given parent instance |
|
|
|
|
|
* or a simple no-arg constructor is used to create an instance of the |
|
|
|
|
|
* specified element type. |
|
|
|
|
|
* |
|
|
|
|
|
* @param project Project to which the parent object belongs. |
|
|
|
|
|
* Must not be <code>null</code>. If the resulting |
|
|
|
|
|
* object is an instance of ProjectComponent, its |
|
|
|
|
|
* Project reference is set to this parameter value. |
|
|
|
|
|
* @param parent Parent object used to create the instance. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* @param elementName Name of the element to create an instance of. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @return an instance of the specified element type |
|
|
|
|
|
* |
|
|
|
|
|
* @exception BuildException if no method is available to create the |
|
|
|
|
|
* element instance, or if the creating method |
|
|
|
|
|
* fails. |
|
|
*/ |
|
|
*/ |
|
|
public Object createElement(Project project, Object element, String elementName) |
|
|
|
|
|
throws BuildException { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Object createElement(Project project, Object parent, |
|
|
|
|
|
String elementName) throws BuildException { |
|
|
|
|
|
NestedCreator nc = (NestedCreator) nestedCreators.get(elementName); |
|
|
|
|
|
if (nc == null && parent instanceof DynamicConfigurator) { |
|
|
|
|
|
DynamicConfigurator dc = (DynamicConfigurator) parent; |
|
|
|
|
|
Object nestedElement = dc.createDynamicElement(elementName); |
|
|
|
|
|
if (nestedElement != null) { |
|
|
|
|
|
if (nestedElement instanceof ProjectComponent) { |
|
|
|
|
|
((ProjectComponent) nestedElement).setProject(project); |
|
|
|
|
|
} |
|
|
|
|
|
return nestedElement; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (nc == null) { |
|
|
|
|
|
String msg = project.getElementName(parent) + |
|
|
|
|
|
" doesn't support the nested \"" + elementName + "\" element."; |
|
|
|
|
|
throw new BuildException(msg); |
|
|
|
|
|
} |
|
|
try { |
|
|
try { |
|
|
// First check if there are any roles supported by this class |
|
|
|
|
|
Object nestedElement = project.createInRole(element, elementName); |
|
|
|
|
|
if (nestedElement == null) { |
|
|
|
|
|
NestedCreator nc = |
|
|
|
|
|
(NestedCreator) nestedCreators.get(elementName); |
|
|
|
|
|
if (nc == null) { |
|
|
|
|
|
String msg = getElementName(project, element) + |
|
|
|
|
|
" doesn't support the nested \"" + elementName + |
|
|
|
|
|
"\" element."; |
|
|
|
|
|
throw new BuildException(msg); |
|
|
|
|
|
} |
|
|
|
|
|
nestedElement = nc.create(element); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
Object nestedElement = nc.create(parent); |
|
|
if (nestedElement instanceof ProjectComponent) { |
|
|
if (nestedElement instanceof ProjectComponent) { |
|
|
((ProjectComponent) nestedElement).setProject(project); |
|
|
((ProjectComponent) nestedElement).setProject(project); |
|
|
} |
|
|
} |
|
@@ -389,19 +564,48 @@ public class IntrospectionHelper implements BuildListener { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Creates a named nested element. |
|
|
|
|
|
|
|
|
* Indicate if this element supports a nested element of the |
|
|
|
|
|
* given name. |
|
|
|
|
|
* |
|
|
|
|
|
* @param elementName the name of the nested element being checked |
|
|
|
|
|
* |
|
|
|
|
|
* @return true if the given nested element is supported |
|
|
*/ |
|
|
*/ |
|
|
public void storeElement(Project project, Object element, Object child, String elementName) |
|
|
|
|
|
throws BuildException { |
|
|
|
|
|
|
|
|
public boolean supportsNestedElement(String elementName) { |
|
|
|
|
|
return nestedCreators.containsKey(elementName); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Stores a named nested element using a storage method determined |
|
|
|
|
|
* by the initial introspection. If no appropriate storage method |
|
|
|
|
|
* is available, this method returns immediately. |
|
|
|
|
|
* |
|
|
|
|
|
* @param project Ignored in this implementation. |
|
|
|
|
|
* May be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @param parent Parent instance to store the child in. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @param child Child instance to store in the parent. |
|
|
|
|
|
* Should not be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @param elementName Name of the child element to store. |
|
|
|
|
|
* May be <code>null</code>, in which case |
|
|
|
|
|
* this method returns immediately. |
|
|
|
|
|
* |
|
|
|
|
|
* @exception BuildException if the storage method fails. |
|
|
|
|
|
*/ |
|
|
|
|
|
public void storeElement(Project project, Object parent, Object child, |
|
|
|
|
|
String elementName) throws BuildException { |
|
|
if (elementName == null) { |
|
|
if (elementName == null) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
NestedStorer ns = (NestedStorer)nestedStorers.get(elementName); |
|
|
|
|
|
|
|
|
NestedStorer ns = (NestedStorer) nestedStorers.get(elementName); |
|
|
if (ns == null) { |
|
|
if (ns == null) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
try { |
|
|
try { |
|
|
ns.store(element, child); |
|
|
|
|
|
|
|
|
ns.store(parent, child); |
|
|
} catch (IllegalAccessException ie) { |
|
|
} catch (IllegalAccessException ie) { |
|
|
// impossible as getMethods should only return public methods |
|
|
// impossible as getMethods should only return public methods |
|
|
throw new BuildException(ie); |
|
|
throw new BuildException(ie); |
|
@@ -418,7 +622,16 @@ public class IntrospectionHelper implements BuildListener { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* returns the type of a named nested element. |
|
|
|
|
|
|
|
|
* Returns the type of a named nested element. |
|
|
|
|
|
* |
|
|
|
|
|
* @param elementName The name of the element to find the type of. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @return the type of the nested element with the specified name. |
|
|
|
|
|
* This will never be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @exception BuildException if the introspected class does not |
|
|
|
|
|
* support the named nested element. |
|
|
*/ |
|
|
*/ |
|
|
public Class getElementType(String elementName) |
|
|
public Class getElementType(String elementName) |
|
|
throws BuildException { |
|
|
throws BuildException { |
|
@@ -432,7 +645,16 @@ public class IntrospectionHelper implements BuildListener { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* returns the type of a named attribute. |
|
|
|
|
|
|
|
|
* Returns the type of a named attribute. |
|
|
|
|
|
* |
|
|
|
|
|
* @param attributeName The name of the attribute to find the type of. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @return the type of the attribute with the specified name. |
|
|
|
|
|
* This will never be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @exception BuildException if the introspected class does not |
|
|
|
|
|
* support the named attribute. |
|
|
*/ |
|
|
*/ |
|
|
public Class getAttributeType(String attributeName) |
|
|
public Class getAttributeType(String attributeName) |
|
|
throws BuildException { |
|
|
throws BuildException { |
|
@@ -446,35 +668,77 @@ public class IntrospectionHelper implements BuildListener { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Does the introspected class support PCDATA? |
|
|
|
|
|
|
|
|
* Returns whether or not the introspected class supports PCDATA. |
|
|
|
|
|
* |
|
|
|
|
|
* @return whether or not the introspected class supports PCDATA. |
|
|
*/ |
|
|
*/ |
|
|
public boolean supportsCharacters() { |
|
|
public boolean supportsCharacters() { |
|
|
return addText != null; |
|
|
return addText != null; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Return all attribues supported by the introspected class. |
|
|
|
|
|
|
|
|
* Returns an enumeration of the names of the attributes supported |
|
|
|
|
|
* by the introspected class. |
|
|
|
|
|
* |
|
|
|
|
|
* @return an enumeration of the names of the attributes supported |
|
|
|
|
|
* by the introspected class. |
|
|
*/ |
|
|
*/ |
|
|
public Enumeration getAttributes() { |
|
|
public Enumeration getAttributes() { |
|
|
return attributeSetters.keys(); |
|
|
return attributeSetters.keys(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Return all nested elements supported by the introspected class. |
|
|
|
|
|
|
|
|
* Returns an enumeration of the names of the nested elements supported |
|
|
|
|
|
* by the introspected class. |
|
|
|
|
|
* |
|
|
|
|
|
* @return an enumeration of the names of the nested elements supported |
|
|
|
|
|
* by the introspected class. |
|
|
*/ |
|
|
*/ |
|
|
public Enumeration getNestedElements() { |
|
|
public Enumeration getNestedElements() { |
|
|
return nestedTypes.keys(); |
|
|
return nestedTypes.keys(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Create a proper implementation of AttributeSetter for the given |
|
|
|
|
|
* attribute type. |
|
|
|
|
|
|
|
|
* Creates an implementation of AttributeSetter for the given |
|
|
|
|
|
* attribute type. Conversions (where necessary) are automatically |
|
|
|
|
|
* made for the following types: |
|
|
|
|
|
* <ul> |
|
|
|
|
|
* <li>String (left as it is) |
|
|
|
|
|
* <li>Character/char (first character is used) |
|
|
|
|
|
* <li>Boolean/boolean |
|
|
|
|
|
* ({@link Project#toBoolean(String) Project.toBoolean(String)} is used) |
|
|
|
|
|
* <li>Class (Class.forName is used) |
|
|
|
|
|
* <li>File (resolved relative to the appropriate project) |
|
|
|
|
|
* <li>Path (resolve relative to the appropriate project) |
|
|
|
|
|
* <li>EnumeratedAttribute (uses its own |
|
|
|
|
|
* {@link EnumeratedAttribute#setValue(String) setValue} method) |
|
|
|
|
|
* <li>Other primitive types (wrapper classes are used with constructors |
|
|
|
|
|
* taking String) |
|
|
|
|
|
* </ul> |
|
|
|
|
|
* |
|
|
|
|
|
* If none of the above covers the given parameters, a constructor for the |
|
|
|
|
|
* appropriate class taking a String parameter is used if it is available. |
|
|
|
|
|
* |
|
|
|
|
|
* @param m The method to invoke on the bean when the setter is invoked. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* @param arg The type of the single argument of the bean's method. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* @param attrName the name of the attribute for which the setter is being |
|
|
|
|
|
* created. |
|
|
|
|
|
* |
|
|
|
|
|
* @return an appropriate AttributeSetter instance, or <code>null</code> |
|
|
|
|
|
* if no appropriate conversion is available. |
|
|
*/ |
|
|
*/ |
|
|
private AttributeSetter createAttributeSetter(final Method m, |
|
|
private AttributeSetter createAttributeSetter(final Method m, |
|
|
final Class arg) { |
|
|
|
|
|
|
|
|
Class arg, |
|
|
|
|
|
final String attrName) { |
|
|
|
|
|
// use wrappers for primitive classes, e.g. int and |
|
|
|
|
|
// Integer are treated identically |
|
|
|
|
|
final Class reflectedArg = PRIMITIVE_TYPE_MAP.containsKey (arg) |
|
|
|
|
|
? (Class) PRIMITIVE_TYPE_MAP.get(arg) : arg; |
|
|
|
|
|
|
|
|
// simplest case - setAttribute expects String |
|
|
// simplest case - setAttribute expects String |
|
|
if (java.lang.String.class.equals(arg)) { |
|
|
|
|
|
|
|
|
if (java.lang.String.class.equals(reflectedArg)) { |
|
|
return new AttributeSetter() { |
|
|
return new AttributeSetter() { |
|
|
public void set(Project p, Object parent, String value) |
|
|
public void set(Project p, Object parent, String value) |
|
|
throws InvocationTargetException, IllegalAccessException { |
|
|
throws InvocationTargetException, IllegalAccessException { |
|
@@ -482,69 +746,23 @@ public class IntrospectionHelper implements BuildListener { |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
// now for the primitive types, use their wrappers |
|
|
|
|
|
} else if (java.lang.Character.class.equals(arg) |
|
|
|
|
|
|| java.lang.Character.TYPE.equals(arg)) { |
|
|
|
|
|
|
|
|
// char and Character get special treatment - take the first character |
|
|
|
|
|
} else if (java.lang.Character.class.equals(reflectedArg)) { |
|
|
return new AttributeSetter() { |
|
|
return new AttributeSetter() { |
|
|
public void set(Project p, Object parent, String value) |
|
|
public void set(Project p, Object parent, String value) |
|
|
throws InvocationTargetException, IllegalAccessException { |
|
|
throws InvocationTargetException, IllegalAccessException { |
|
|
|
|
|
if (value.length() == 0) { |
|
|
|
|
|
throw new BuildException("The value \"\" is not a " |
|
|
|
|
|
+ "legal value for attribute \"" |
|
|
|
|
|
+ attrName + "\""); |
|
|
|
|
|
} |
|
|
m.invoke(parent, new Character[] {new Character(value.charAt(0))}); |
|
|
m.invoke(parent, new Character[] {new Character(value.charAt(0))}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
}; |
|
|
}; |
|
|
} else if (java.lang.Byte.TYPE.equals(arg)) { |
|
|
|
|
|
return new AttributeSetter() { |
|
|
|
|
|
public void set(Project p, Object parent, String value) |
|
|
|
|
|
throws InvocationTargetException, IllegalAccessException { |
|
|
|
|
|
m.invoke(parent, new Byte[] {new Byte(value)}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
} else if (java.lang.Short.TYPE.equals(arg)) { |
|
|
|
|
|
return new AttributeSetter() { |
|
|
|
|
|
public void set(Project p, Object parent, String value) |
|
|
|
|
|
throws InvocationTargetException, IllegalAccessException { |
|
|
|
|
|
m.invoke(parent, new Short[] {new Short(value)}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
} else if (java.lang.Integer.TYPE.equals(arg)) { |
|
|
|
|
|
return new AttributeSetter() { |
|
|
|
|
|
public void set(Project p, Object parent, String value) |
|
|
|
|
|
throws InvocationTargetException, IllegalAccessException { |
|
|
|
|
|
m.invoke(parent, new Integer[] {new Integer(value)}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
} else if (java.lang.Long.TYPE.equals(arg)) { |
|
|
|
|
|
return new AttributeSetter() { |
|
|
|
|
|
public void set(Project p, Object parent, String value) |
|
|
|
|
|
throws InvocationTargetException, IllegalAccessException { |
|
|
|
|
|
m.invoke(parent, new Long[] {new Long(value)}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
} else if (java.lang.Float.TYPE.equals(arg)) { |
|
|
|
|
|
return new AttributeSetter() { |
|
|
|
|
|
public void set(Project p, Object parent, String value) |
|
|
|
|
|
throws InvocationTargetException, IllegalAccessException { |
|
|
|
|
|
m.invoke(parent, new Float[] {new Float(value)}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
} else if (java.lang.Double.TYPE.equals(arg)) { |
|
|
|
|
|
return new AttributeSetter() { |
|
|
|
|
|
public void set(Project p, Object parent, String value) |
|
|
|
|
|
throws InvocationTargetException, IllegalAccessException { |
|
|
|
|
|
m.invoke(parent, new Double[] {new Double(value)}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// boolean gets an extra treatment, because we have a nice method |
|
|
|
|
|
// in Project |
|
|
|
|
|
} else if (java.lang.Boolean.class.equals(arg) |
|
|
|
|
|
|| java.lang.Boolean.TYPE.equals(arg)) { |
|
|
|
|
|
|
|
|
// boolean and Boolean get special treatment because we |
|
|
|
|
|
// have a nice method in Project |
|
|
|
|
|
} else if (java.lang.Boolean.class.equals(reflectedArg)) { |
|
|
return new AttributeSetter() { |
|
|
return new AttributeSetter() { |
|
|
public void set(Project p, Object parent, String value) |
|
|
public void set(Project p, Object parent, String value) |
|
|
throws InvocationTargetException, IllegalAccessException { |
|
|
throws InvocationTargetException, IllegalAccessException { |
|
@@ -555,7 +773,7 @@ public class IntrospectionHelper implements BuildListener { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
// Class doesn't have a String constructor but a decent factory method |
|
|
// Class doesn't have a String constructor but a decent factory method |
|
|
} else if (java.lang.Class.class.equals(arg)) { |
|
|
|
|
|
|
|
|
} else if (java.lang.Class.class.equals(reflectedArg)) { |
|
|
return new AttributeSetter() { |
|
|
return new AttributeSetter() { |
|
|
public void set(Project p, Object parent, String value) |
|
|
public void set(Project p, Object parent, String value) |
|
|
throws InvocationTargetException, IllegalAccessException, BuildException { |
|
|
throws InvocationTargetException, IllegalAccessException, BuildException { |
|
@@ -568,7 +786,7 @@ public class IntrospectionHelper implements BuildListener { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
// resolve relative paths through Project |
|
|
// resolve relative paths through Project |
|
|
} else if (java.io.File.class.equals(arg)) { |
|
|
|
|
|
|
|
|
} else if (java.io.File.class.equals(reflectedArg)) { |
|
|
return new AttributeSetter() { |
|
|
return new AttributeSetter() { |
|
|
public void set(Project p, Object parent, String value) |
|
|
public void set(Project p, Object parent, String value) |
|
|
throws InvocationTargetException, IllegalAccessException { |
|
|
throws InvocationTargetException, IllegalAccessException { |
|
@@ -578,7 +796,7 @@ public class IntrospectionHelper implements BuildListener { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
// resolve relative paths through Project |
|
|
// resolve relative paths through Project |
|
|
} else if (org.apache.tools.ant.types.Path.class.equals(arg)) { |
|
|
|
|
|
|
|
|
} else if (org.apache.tools.ant.types.Path.class.equals(reflectedArg)) { |
|
|
return new AttributeSetter() { |
|
|
return new AttributeSetter() { |
|
|
public void set(Project p, Object parent, String value) |
|
|
public void set(Project p, Object parent, String value) |
|
|
throws InvocationTargetException, IllegalAccessException { |
|
|
throws InvocationTargetException, IllegalAccessException { |
|
@@ -588,12 +806,13 @@ public class IntrospectionHelper implements BuildListener { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
// EnumeratedAttributes have their own helper class |
|
|
// EnumeratedAttributes have their own helper class |
|
|
} else if (org.apache.tools.ant.types.EnumeratedAttribute.class.isAssignableFrom(arg)) { |
|
|
|
|
|
|
|
|
} else if (org.apache.tools.ant.types.EnumeratedAttribute.class.isAssignableFrom(reflectedArg)) { |
|
|
return new AttributeSetter() { |
|
|
return new AttributeSetter() { |
|
|
public void set(Project p, Object parent, String value) |
|
|
public void set(Project p, Object parent, String value) |
|
|
throws InvocationTargetException, IllegalAccessException, BuildException { |
|
|
throws InvocationTargetException, IllegalAccessException, BuildException { |
|
|
try { |
|
|
try { |
|
|
org.apache.tools.ant.types.EnumeratedAttribute ea = (org.apache.tools.ant.types.EnumeratedAttribute)arg.newInstance(); |
|
|
|
|
|
|
|
|
org.apache.tools.ant.types.EnumeratedAttribute ea = |
|
|
|
|
|
(org.apache.tools.ant.types.EnumeratedAttribute) reflectedArg.newInstance(); |
|
|
ea.setValue(value); |
|
|
ea.setValue(value); |
|
|
m.invoke(parent, new EnumeratedAttribute[] {ea}); |
|
|
m.invoke(parent, new EnumeratedAttribute[] {ea}); |
|
|
} catch (InstantiationException ie) { |
|
|
} catch (InstantiationException ie) { |
|
@@ -603,11 +822,13 @@ public class IntrospectionHelper implements BuildListener { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
// worst case. look for a public String constructor and use it |
|
|
// worst case. look for a public String constructor and use it |
|
|
|
|
|
// This is used (deliberately) for all primitives/wrappers other than |
|
|
|
|
|
// char and boolean |
|
|
} else { |
|
|
} else { |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
final Constructor c = |
|
|
final Constructor c = |
|
|
arg.getConstructor(new Class[] {java.lang.String.class}); |
|
|
|
|
|
|
|
|
reflectedArg.getConstructor(new Class[] {java.lang.String.class}); |
|
|
|
|
|
|
|
|
return new AttributeSetter() { |
|
|
return new AttributeSetter() { |
|
|
public void set(Project p, Object parent, |
|
|
public void set(Project p, Object parent, |
|
@@ -632,63 +853,76 @@ public class IntrospectionHelper implements BuildListener { |
|
|
return null; |
|
|
return null; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
protected String getElementName(Project project, Object element) |
|
|
|
|
|
{ |
|
|
|
|
|
Hashtable elements = project.getTaskDefinitions(); |
|
|
|
|
|
String typeName = "task"; |
|
|
|
|
|
if (!elements.contains( element.getClass() )) |
|
|
|
|
|
{ |
|
|
|
|
|
elements = project.getDataTypeDefinitions(); |
|
|
|
|
|
typeName = "data type"; |
|
|
|
|
|
if (!elements.contains( element.getClass() )) |
|
|
|
|
|
{ |
|
|
|
|
|
elements = null; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (elements != null) |
|
|
|
|
|
{ |
|
|
|
|
|
Enumeration e = elements.keys(); |
|
|
|
|
|
while (e.hasMoreElements()) |
|
|
|
|
|
{ |
|
|
|
|
|
String elementName = (String) e.nextElement(); |
|
|
|
|
|
Class elementClass = (Class) elements.get( elementName ); |
|
|
|
|
|
if ( element.getClass().equals( elementClass ) ) |
|
|
|
|
|
{ |
|
|
|
|
|
return "The <" + elementName + "> " + typeName; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return "Class " + element.getClass().getName(); |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Returns a description of the type of the given element in |
|
|
|
|
|
* relation to a given project. This is used for logging purposes |
|
|
|
|
|
* when the element is asked to cope with some data it has no |
|
|
|
|
|
* way of handling. |
|
|
|
|
|
* |
|
|
|
|
|
* @param project The project the element is defined in. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @param element The element to describe. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @return a description of the element type |
|
|
|
|
|
*/ |
|
|
|
|
|
protected String getElementName(Project project, Object element) { |
|
|
|
|
|
return project.getElementName(element); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* extract the name of a property from a method name - subtracting |
|
|
|
|
|
* a given prefix. |
|
|
|
|
|
|
|
|
* Extracts the name of a property from a method name by subtracting |
|
|
|
|
|
* a given prefix and converting into lower case. It is up to calling |
|
|
|
|
|
* code to make sure the method name does actually begin with the |
|
|
|
|
|
* specified prefix - no checking is done in this method. |
|
|
|
|
|
* |
|
|
|
|
|
* @param methodName The name of the method in question. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* @param prefix The prefix to remove. |
|
|
|
|
|
* Must not be <code>null</code>. |
|
|
|
|
|
* |
|
|
|
|
|
* @return the lower-cased method name with the prefix removed. |
|
|
*/ |
|
|
*/ |
|
|
private String getPropertyName(String methodName, String prefix) { |
|
|
private String getPropertyName(String methodName, String prefix) { |
|
|
int start = prefix.length(); |
|
|
int start = prefix.length(); |
|
|
return methodName.substring(start).toLowerCase(Locale.US); |
|
|
return methodName.substring(start).toLowerCase(Locale.US); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Internal interface used to create nested elements. Not documented |
|
|
|
|
|
* in detail for reasons of source code readability. |
|
|
|
|
|
*/ |
|
|
private interface NestedCreator { |
|
|
private interface NestedCreator { |
|
|
Object create(Object parent) |
|
|
Object create(Object parent) |
|
|
throws InvocationTargetException, IllegalAccessException, InstantiationException; |
|
|
throws InvocationTargetException, IllegalAccessException, InstantiationException; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Internal interface used to storing nested elements. Not documented |
|
|
|
|
|
* in detail for reasons of source code readability. |
|
|
|
|
|
*/ |
|
|
private interface NestedStorer { |
|
|
private interface NestedStorer { |
|
|
void store(Object parent, Object child) |
|
|
void store(Object parent, Object child) |
|
|
throws InvocationTargetException, IllegalAccessException, InstantiationException; |
|
|
throws InvocationTargetException, IllegalAccessException, InstantiationException; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Internal interface used to setting element attributes. Not documented |
|
|
|
|
|
* in detail for reasons of source code readability. |
|
|
|
|
|
*/ |
|
|
private interface AttributeSetter { |
|
|
private interface AttributeSetter { |
|
|
void set(Project p, Object parent, String value) |
|
|
void set(Project p, Object parent, String value) |
|
|
throws InvocationTargetException, IllegalAccessException, |
|
|
throws InvocationTargetException, IllegalAccessException, |
|
|
BuildException; |
|
|
BuildException; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public void buildStarted(BuildEvent event) {} |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Clears all storage used by this class, including the static cache of |
|
|
|
|
|
* helpers. |
|
|
|
|
|
* |
|
|
|
|
|
* @param event Ignored in this implementation. |
|
|
|
|
|
*/ |
|
|
public void buildFinished(BuildEvent event) { |
|
|
public void buildFinished(BuildEvent event) { |
|
|
attributeTypes.clear(); |
|
|
attributeTypes.clear(); |
|
|
attributeSetters.clear(); |
|
|
attributeSetters.clear(); |
|
@@ -698,9 +932,44 @@ public class IntrospectionHelper implements BuildListener { |
|
|
helpers.clear(); |
|
|
helpers.clear(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Empty implementation to satisfy the BuildListener interface. |
|
|
|
|
|
* @param event Ignored in this implementation. |
|
|
|
|
|
*/ |
|
|
|
|
|
public void buildStarted(BuildEvent event) {} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Empty implementation to satisfy the BuildListener interface. |
|
|
|
|
|
* |
|
|
|
|
|
* @param event Ignored in this implementation. |
|
|
|
|
|
*/ |
|
|
public void targetStarted(BuildEvent event) {} |
|
|
public void targetStarted(BuildEvent event) {} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Empty implementation to satisfy the BuildListener interface. |
|
|
|
|
|
* |
|
|
|
|
|
* @param event Ignored in this implementation. |
|
|
|
|
|
*/ |
|
|
public void targetFinished(BuildEvent event) {} |
|
|
public void targetFinished(BuildEvent event) {} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Empty implementation to satisfy the BuildListener interface. |
|
|
|
|
|
* |
|
|
|
|
|
* @param event Ignored in this implementation. |
|
|
|
|
|
*/ |
|
|
public void taskStarted(BuildEvent event) {} |
|
|
public void taskStarted(BuildEvent event) {} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Empty implementation to satisfy the BuildListener interface. |
|
|
|
|
|
* |
|
|
|
|
|
* @param event Ignored in this implementation. |
|
|
|
|
|
*/ |
|
|
public void taskFinished(BuildEvent event) {} |
|
|
public void taskFinished(BuildEvent event) {} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Empty implementation to satisfy the BuildListener interface. |
|
|
|
|
|
* |
|
|
|
|
|
* @param event Ignored in this implementation. |
|
|
|
|
|
*/ |
|
|
public void messageLogged(BuildEvent event) {} |
|
|
public void messageLogged(BuildEvent event) {} |
|
|
} |
|
|
} |