@@ -119,6 +119,24 @@ public class IntrospectionHelper implements BuildListener {
*/
*/
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
// XXX: (Jon Skeet) The documentation below doesn't draw a clear
// distinction between addConfigured and add. It's obvious what the
// distinction between addConfigured and add. It's obvious what the
// code *here* does (addConfigured sets both a creator method which
// code *here* does (addConfigured sets both a creator method which
@@ -607,14 +625,6 @@ public class IntrospectionHelper implements BuildListener {
}
}
/**
/**
// XXX: (Jon Skeet) This method implementation could be made much simpler
// using a mapping from Integer.TYPE to Integer.class etc, so
// that when a primitive type is given, the wrapper is just
// automatically used. This would then fall through to the "worst case"
// where a string constructor is used - but this is what happens
// for Integer etc anyway. There would be a slight speed difference (due
// to using reflection where it's currently not being used), but the
// size of the code for this method would be reduced by 50 lines :)
* Creates an implementation of AttributeSetter for the given
* Creates an implementation of AttributeSetter for the given
* attribute type. Conversions (where necessary) are automatically
* attribute type. Conversions (where necessary) are automatically
* made for the following types:
* made for the following types:
@@ -637,17 +647,20 @@ public class IntrospectionHelper implements BuildListener {
*
*
* @param m The method to invoke on the bean when the setter is invoked.
* @param m The method to invoke on the bean when the setter is invoked.
* Must not be <code>null</code>.
* Must not be <code>null</code>.
* @param arg The type of the single argument passed to the bean's method
* when the returned setter is invoked .
* @param arg The type of the single argument of the bean's method.
* Must not be <code>null</code> .
*
*
* @return an appropriate AttributeSetter instance, or <code>null</code>
* @return an appropriate AttributeSetter instance, or <code>null</code>
* if no appropriate conversion is available.
* if no appropriate conversion is available.
*/
*/
private AttributeSetter createAttributeSetter(final Method m,
private AttributeSetter createAttributeSetter(final Method m,
final Class arg) {
Class arg) {
// 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(reflectedA rg)) {
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 {
@@ -655,9 +668,8 @@ 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 {
@@ -665,59 +677,9 @@ public class IntrospectionHelper implements BuildListener {
}
}
};
};
} 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
// boolean and Boolean get special treatment because we have a nice method
// in Project
// in Project
} else if (java.lang.Boolean.class.equals(arg)
|| java.lang.Boolean.TYPE.equals(arg)) {
} 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 {
@@ -728,7 +690,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(a rg)) {
} else if (java.lang.Class.class.equals(reflectedA rg)) {
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 {
@@ -741,7 +703,7 @@ public class IntrospectionHelper implements BuildListener {
};
};
// resolve relative paths through Project
// resolve relative paths through Project
} else if (java.io.File.class.equals(a rg)) {
} else if (java.io.File.class.equals(reflectedA rg)) {
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 {
@@ -751,7 +713,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(a rg)) {
} else if (org.apache.tools.ant.types.Path.class.equals(reflectedA rg)) {
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 {
@@ -761,12 +723,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(a rg)) {
} else if (org.apache.tools.ant.types.EnumeratedAttribute.class.isAssignableFrom(reflectedA rg)) {
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) {
@@ -776,11 +739,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 =
a rg.getConstructor(new Class[] {java.lang.String.class});
reflectedA rg.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,