in src/main/org/apache/tools/ant/IntrospectionHelper.java [1038:1275]
private AttributeSetter createAttributeSetter(final Method m,
final Class<?> arg,
final String attrName) {
if (Optional.class.equals(arg)) {
Type gpt = m.getGenericParameterTypes()[0];
Class<?> payload = Object.class;
if (gpt instanceof ParameterizedType ) {
Type ata = ((ParameterizedType) gpt).getActualTypeArguments()[0];
if (ata instanceof Class<?>) {
payload = (Class<?>) ata;
} else if (ata instanceof ParameterizedType) {
payload = (Class<?>) ((ParameterizedType) ata).getRawType();
}
}
final AttributeSetter wrapped = createAttributeSetter(m, payload, attrName);
return new AttributeSetter(m, arg, Optional::empty) {
@Override
Optional<?> toTargetType(Project project, String value)
throws BuildException {
return Optional.ofNullable(wrapped.toTargetType(project, value));
}
};
}
if (OptionalInt.class.equals(arg)) {
final AttributeSetter wrapped = createAttributeSetter(m, Integer.class, attrName);
return new AttributeSetter(m, arg, OptionalInt::empty) {
@Override
OptionalInt toTargetType(Project project, String value)
throws BuildException {
return Optional.ofNullable((Integer) wrapped.toTargetType(project, value))
.map(OptionalInt::of).orElseGet(OptionalInt::empty);
}
};
}
if (OptionalLong.class.equals(arg)) {
final AttributeSetter wrapped = createAttributeSetter(m, Long.class, attrName);
return new AttributeSetter(m, arg, OptionalLong::empty) {
@Override
OptionalLong toTargetType(Project project, String value)
throws BuildException {
return Optional.ofNullable((Long) wrapped.toTargetType(project, value))
.map(OptionalLong::of).orElseGet(OptionalLong::empty);
}
};
}
if (OptionalDouble.class.equals(arg)) {
final AttributeSetter wrapped = createAttributeSetter(m, Double.class, attrName);
return new AttributeSetter(m, arg, OptionalDouble::empty) {
@Override
Object toTargetType(Project project, String value)
throws BuildException {
return Optional.ofNullable((Double) wrapped.toTargetType(project, value))
.map(OptionalDouble::of).orElseGet(OptionalDouble::empty);
}
};
}
// use wrappers for primitive classes, e.g. int and
// Integer are treated identically
final Class<?> reflectedArg = PRIMITIVE_TYPE_MAP.getOrDefault(arg, arg);
// Object.class - it gets handled differently by AttributeSetter
if (Object.class == reflectedArg) {
return new AttributeSetter(m, arg) {
@Override
Object toTargetType(Project project, String value)
throws BuildException {
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 String toTargetType(Project project, String t) {
return t;
}
};
}
// char and Character get special treatment - take the first character
if (Character.class.equals(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
public Character toTargetType(Project project, String value) {
if (value.isEmpty()) {
throw new BuildException("The value \"\" is not a "
+ "legal value for attribute \"" + attrName + "\"");
}
return Character.valueOf(value.charAt(0));
}
};
}
// boolean and Boolean get special treatment because we have a nice method in Project
if (Boolean.class.equals(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
public Boolean toTargetType(Project project, String value) {
return Boolean.valueOf(Project.toBoolean(value));
}
};
}
// Class doesn't have a String constructor but a decent factory method
if (Class.class.equals(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
public Class<?> toTargetType(Project project, String value) {
try {
return Class.forName(value);
} catch (ClassNotFoundException e) {
throw new BuildException(e);
}
}
};
}
// resolve relative paths through Project
if (File.class.equals(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
Object toTargetType(Project project, String value)
throws BuildException {
return project.resolveFile(value);
}
};
}
// resolve relative nio paths through Project
if (java.nio.file.Path.class.equals(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
Object toTargetType(Project project, String value)
throws BuildException {
return project.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
Object toTargetType(Project project, String value)
throws BuildException {
return new FileResource(project.resolveFile(value));
}
};
}
// EnumeratedAttributes have their own helper class
if (EnumeratedAttribute.class.isAssignableFrom(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
public EnumeratedAttribute toTargetType(Project project, String value) {
EnumeratedAttribute ea;
try {
ea = (EnumeratedAttribute) reflectedArg.getDeclaredConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
throw BuildException.of(e);
}
ea.setValue(value);
return ea;
}
};
}
final AttributeSetter setter = getEnumSetter(reflectedArg, m, arg);
if (setter != null) {
return setter;
}
if (Long.class.equals(reflectedArg)) {
return new AttributeSetter(m, arg) {
@Override
public Long toTargetType(Project project, String value) {
try {
return Long.valueOf(StringUtils.parseHumanSizes(value));
} catch (final NumberFormatException e) {
throw new BuildException(
String.format("Can't assign non-numeric value '%s' to attribute %s",
value, attrName));
} 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 Object toTargetType(Project project, String value) {
try {
final Object[] args = finalIncludeProject
? new Object[] {project, value} : new Object[] {value};
final Object attribute = finalConstructor.newInstance(args);
if (project != null) {
project.setProjectReference(attribute);
}
return attribute;
} catch (final Exception e) {
Throwable thw = e;
while (true) {
if (thw instanceof IllegalArgumentException) {
throw new BuildException(String.format(
"Can't convert value '%s' to type %s, reason: %s with message '%s'",
value, reflectedArg, thw.getClass(), thw.getMessage()));
}
final Throwable _thw = thw;
Optional<Throwable> next = Optional.of(thw).map(Throwable::getCause).filter(t -> t != _thw);
if (!next.isPresent()) {
break;
}
thw = next.get();
}
throw BuildException.of(e);
}
}
};
}