Search in sources :

Example 1 with Property

use of org.gradle.api.provider.Property in project gradle by gradle.

the class AbstractClassGenerator method generateUnderLock.

private <T> Class<? extends T> generateUnderLock(Class<T> type) {
    Map<Class<?>, Class<?>> cache = GENERATED_CLASSES.get(getClass());
    if (cache == null) {
        // WeakHashMap won't work here. It keeps a strong reference to the mapping value, which is the generated class in this case
        // However, the generated class has a strong reference to the source class (by extending it), so the keys will always be
        // strongly reachable while this Class is strongly reachable. Use weak references for both key and value of the mapping instead.
        cache = new ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK);
        GENERATED_CLASSES.put(getClass(), cache);
    }
    Class<?> generatedClass = cache.get(type);
    if (generatedClass != null) {
        return generatedClass.asSubclass(type);
    }
    int modifiers = type.getModifiers();
    if (Modifier.isPrivate(modifiers)) {
        throw new GradleException(String.format("Cannot create a proxy class for private class '%s'.", type.getSimpleName()));
    }
    if (Modifier.isAbstract(modifiers)) {
        throw new GradleException(String.format("Cannot create a proxy class for abstract class '%s'.", type.getSimpleName()));
    }
    if (Modifier.isFinal(modifiers)) {
        throw new GradleException(String.format("Cannot create a proxy class for final class '%s'.", type.getSimpleName()));
    }
    Class<? extends T> subclass;
    try {
        ClassMetaData classMetaData = inspectType(type);
        ClassBuilder<T> builder = start(type, classMetaData);
        builder.startClass(classMetaData.isShouldImplementWithServiceRegistry());
        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;
            }
        }
        if (classMetaData.isShouldImplementWithServiceRegistry()) {
            builder.generateServiceRegistrySupportMethods();
        }
        Set<PropertyMetaData> conventionProperties = new HashSet<PropertyMetaData>();
        for (PropertyMetaData property : classMetaData.properties.values()) {
            if (SKIP_PROPERTIES.contains(property.name)) {
                continue;
            }
            if (!property.getters.isEmpty() && (Property.class.isAssignableFrom(property.getType()) || HasMultipleValues.class.isAssignableFrom(property.getType()))) {
                builder.addPropertySetters(property, property.getters.get(0));
                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);
                }
                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;
}
Also used : HasMultipleValues(org.gradle.api.provider.HasMultipleValues) Property(org.gradle.api.provider.Property) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) ReferenceMap(org.apache.commons.collections.map.ReferenceMap) AbstractReferenceMap(org.apache.commons.collections.map.AbstractReferenceMap) Method(java.lang.reflect.Method) GroovyObject(groovy.lang.GroovyObject) GradleException(org.gradle.api.GradleException) GroovyObject(groovy.lang.GroovyObject)

Aggregations

GroovyObject (groovy.lang.GroovyObject)1 Method (java.lang.reflect.Method)1 HashSet (java.util.HashSet)1 LinkedHashSet (java.util.LinkedHashSet)1 AbstractReferenceMap (org.apache.commons.collections.map.AbstractReferenceMap)1 ReferenceMap (org.apache.commons.collections.map.ReferenceMap)1 GradleException (org.gradle.api.GradleException)1 HasMultipleValues (org.gradle.api.provider.HasMultipleValues)1 Property (org.gradle.api.provider.Property)1