if (generatedClass != null) {
return generatedClass.asSubclass(type);
}
if (Modifier.isPrivate(type.getModifiers())) {
throw new GradleException(String.format("Cannot create a proxy class for private class '%s'.",
type.getSimpleName()));
}
if (Modifier.isAbstract(type.getModifiers())) {
throw new GradleException(String.format("Cannot create a proxy class for abstract class '%s'.",
type.getSimpleName()));
}
Class<? extends T> subclass;
try {
ClassMetaData classMetaData = inspectType(type);
ClassBuilder<T> builder = start(type, classMetaData);
builder.startClass();
if (!DynamicObjectAware.class.isAssignableFrom(type)) {
if (ExtensionAware.class.isAssignableFrom(type)) {
throw new UnsupportedOperationException("A type that implements ExtensionAware must currently also implement DynamicObjectAware.");
}
builder.mixInDynamicAware();
}
if (!GroovyObject.class.isAssignableFrom(type)) {
builder.mixInGroovyObject();
}
builder.addDynamicMethods();
if (classMetaData.conventionAware && !IConventionAware.class.isAssignableFrom(type)) {
builder.mixInConventionAware();
}
Class noMappingClass = Object.class;
for (Class<?> c = type; c != null && noMappingClass == Object.class; c = c.getSuperclass()) {
if (c.getAnnotation(NoConventionMapping.class) != null) {
noMappingClass = c;
}
}
Set<PropertyMetaData> conventionProperties = new HashSet<PropertyMetaData>();
for (PropertyMetaData property : classMetaData.properties.values()) {
if (SKIP_PROPERTIES.contains(property.name)) {
continue;
}
if (property.injector) {
builder.addInjectorProperty(property);
for (Method getter : property.getters) {
builder.applyServiceInjectionToGetter(property, getter);
}
for (Method setter : property.setters) {
builder.applyServiceInjectionToSetter(property, setter);
}
continue;
}
boolean needsConventionMapping = false;
if (classMetaData.isExtensible()) {
for (Method getter : property.getters) {
if (!Modifier.isFinal(getter.getModifiers()) && !getter.getDeclaringClass().isAssignableFrom(noMappingClass)) {
needsConventionMapping = true;
break;
}
}
}
if (needsConventionMapping) {
conventionProperties.add(property);
builder.addConventionProperty(property);
for (Method getter : property.getters) {
builder.applyConventionMappingToGetter(property, getter);
}
}
if (needsConventionMapping) {
for (Method setter : property.setters) {
if (!Modifier.isFinal(setter.getModifiers())) {
builder.applyConventionMappingToSetter(property, setter);
}
}
}
}
Set<Method> actionMethods = classMetaData.missingOverloads;
for (Method method : actionMethods) {
builder.addActionMethod(method);
}
// Adds a set method for each mutable property
for (PropertyMetaData property : classMetaData.properties.values()) {
if (property.setters.isEmpty()) {
continue;
}
if (Iterable.class.isAssignableFrom(property.getType())) {
// Currently not supported
continue;
}
if (property.setMethods.isEmpty()) {
for (Method setter : property.setters) {
builder.addSetMethod(property, setter);
}
} else if (conventionProperties.contains(property)) {
for (Method setMethod : property.setMethods) {
builder.applyConventionMappingToSetMethod(property, setMethod);
}
}
}
for (Constructor<?> constructor : type.getConstructors()) {
if (Modifier.isPublic(constructor.getModifiers())) {
builder.addConstructor(constructor);
}
}
subclass = builder.generate();
} catch (Throwable e) {
throw new GradleException(String.format("Could not generate a proxy class for class %s.", type.getName()), e);
}
cache.put(type, subclass);
cache.put(subclass, subclass);
return subclass;