use of org.apache.tools.ant.types.EnumeratedAttribute in project ant by apache.
the class IntrospectionHelper method createAttributeSetter.
/**
* 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>Resource (resolved as a FileResource relative to the appropriate project)
* <li>FileProvider (resolved as a FileResource 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, final 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) ? PRIMITIVE_TYPE_MAP.get(arg) : arg;
// Object.class - it gets handled differently by AttributeSetter
if (java.lang.Object.class == reflectedArg) {
return new AttributeSetter(m, arg) {
@Override
public void set(final Project p, final Object parent, final String value) throws InvocationTargetException, IllegalAccessException {
throw new BuildException("Internal ant problem - this should not get called");
}
};
}
// simplest case - setAttribute expects String
if (String.class.equals(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
public void set(final Project p, final Object parent, final String value) throws InvocationTargetException, IllegalAccessException {
m.invoke(parent, (Object[]) new String[] { value });
}
};
}
// char and Character get special treatment - take the first character
if (java.lang.Character.class.equals(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
public void set(final Project p, final Object parent, final String value) throws InvocationTargetException, IllegalAccessException {
if (value.length() == 0) {
throw new BuildException("The value \"\" is not a " + "legal value for attribute \"" + attrName + "\"");
}
m.invoke(parent, (Object[]) new Character[] { value.charAt(0) });
}
};
}
// boolean and Boolean get special treatment because we have a nice method in Project
if (java.lang.Boolean.class.equals(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
public void set(final Project p, final Object parent, final String value) throws InvocationTargetException, IllegalAccessException {
m.invoke(parent, (Object[]) new Boolean[] { Project.toBoolean(value) ? Boolean.TRUE : Boolean.FALSE });
}
};
}
// Class doesn't have a String constructor but a decent factory method
if (java.lang.Class.class.equals(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
public void set(final Project p, final Object parent, final String value) throws InvocationTargetException, IllegalAccessException, BuildException {
try {
m.invoke(parent, Class.forName(value));
} catch (final ClassNotFoundException ce) {
throw new BuildException(ce);
}
}
};
}
// resolve relative paths through Project
if (java.io.File.class.equals(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
public void set(final Project p, final Object parent, final String value) throws InvocationTargetException, IllegalAccessException {
m.invoke(parent, p.resolveFile(value));
}
};
}
// resolve relative nio paths through Project
if (java.nio.file.Path.class.equals(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
public void set(final Project p, final Object parent, final String value) throws InvocationTargetException, IllegalAccessException {
m.invoke(parent, p.resolveFile(value).toPath());
}
};
}
// resolve Resources/FileProviders as FileResources relative to Project:
if (Resource.class.equals(reflectedArg) || FileProvider.class.equals(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
void set(final Project p, final Object parent, final String value) throws InvocationTargetException, IllegalAccessException, BuildException {
m.invoke(parent, new FileResource(p, p.resolveFile(value)));
}
};
}
// EnumeratedAttributes have their own helper class
if (EnumeratedAttribute.class.isAssignableFrom(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
public void set(final Project p, final Object parent, final String value) throws InvocationTargetException, IllegalAccessException, BuildException {
try {
final EnumeratedAttribute ea = (EnumeratedAttribute) reflectedArg.newInstance();
ea.setValue(value);
m.invoke(parent, ea);
} catch (final InstantiationException ie) {
throw new BuildException(ie);
}
}
};
}
final AttributeSetter setter = getEnumSetter(reflectedArg, m, arg);
if (setter != null) {
return setter;
}
if (java.lang.Long.class.equals(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
public void set(final Project p, final Object parent, final String value) throws InvocationTargetException, IllegalAccessException, BuildException {
try {
m.invoke(parent, StringUtils.parseHumanSizes(value));
} catch (final NumberFormatException e) {
throw new BuildException("Can't assign non-numeric" + " value '" + value + "' to" + " attribute " + attrName);
} catch (final InvocationTargetException e) {
throw e;
} catch (final IllegalAccessException e) {
throw e;
} catch (final Exception e) {
throw new BuildException(e);
}
}
};
}
// worst case. look for a public String constructor and use it
// also supports new Whatever(Project, String) as for Path or Reference
// This is used (deliberately) for all primitives/wrappers other than
// char, boolean, and long.
boolean includeProject;
Constructor<?> c;
try {
// First try with Project.
c = reflectedArg.getConstructor(Project.class, String.class);
includeProject = true;
} catch (final NoSuchMethodException nme) {
// OK, try without.
try {
c = reflectedArg.getConstructor(String.class);
includeProject = false;
} catch (final NoSuchMethodException nme2) {
// Well, no matching constructor.
return null;
}
}
final boolean finalIncludeProject = includeProject;
final Constructor<?> finalConstructor = c;
return new AttributeSetter(m, arg) {
@Override
public void set(final Project p, final Object parent, final String value) throws InvocationTargetException, IllegalAccessException, BuildException {
try {
final Object[] args = finalIncludeProject ? new Object[] { p, value } : new Object[] { value };
final Object attribute = finalConstructor.newInstance(args);
if (p != null) {
p.setProjectReference(attribute);
}
m.invoke(parent, attribute);
} catch (final InvocationTargetException e) {
final Throwable cause = e.getCause();
if (cause instanceof IllegalArgumentException) {
throw new BuildException("Can't assign value '" + value + "' to attribute " + attrName + ", reason: " + cause.getClass() + " with message '" + cause.getMessage() + "'");
}
throw e;
} catch (final InstantiationException ie) {
throw new BuildException(ie);
}
}
};
}
Aggregations