Search in sources :

Example 1 with AsmClassGenerator

use of org.gradle.model.internal.asm.AsmClassGenerator in project gradle by gradle.

the class ManagedCollectionProxyClassGenerator method generate.

/**
 * Generates an implementation of the given managed type.
 *
 * <p>The generated type will:</p>
 *
 * <ul>
 *     <li>extend the given implementation class</li>
 *     <li>implement the given public interface</li>
 *     <li>override each public constructor of the given implementation class</li>
 * </ul>
 */
public Class<?> generate(Class<?> implClass, Class<?> publicContractType) {
    AsmClassGenerator classGenerator = new AsmClassGenerator(publicContractType, "_Impl");
    ClassWriter visitor = classGenerator.getVisitor();
    Type generatedType = classGenerator.getGeneratedType();
    Type superclassType = Type.getType(implClass);
    Type publicType = Type.getType(publicContractType);
    generateClass(visitor, generatedType, superclassType, publicType);
    generateConstructors(visitor, implClass, superclassType);
    visitor.visitEnd();
    return classGenerator.define();
}
Also used : Type(org.objectweb.asm.Type) AsmClassGenerator(org.gradle.model.internal.asm.AsmClassGenerator) ClassWriter(org.objectweb.asm.ClassWriter)

Example 2 with AsmClassGenerator

use of org.gradle.model.internal.asm.AsmClassGenerator in project gradle by gradle.

the class ManagedProxyClassGenerator method generate.

/**
 * Generates an implementation of the given managed type.
 * <p>
 * The generated class will implement/extend the managed type and will:
 * <ul>
 *     <li>provide implementations for abstract getters and setters that delegate to the backing state</li>
 *     <li>provide a `toString()` implementation</li>
 *     <li>mix-in implementation of {@link ManagedInstance}</li>
 *     <li>provide a constructor that accepts a {@link ModelElementState}, which will be used to implement the above.</li>
 * </ul>
 *
 * In case a delegate schema is supplied, the generated class will also have:
 * <ul>
 *     <li>a constructor that also takes a delegate instance</li>
 *     <li>methods that call through to the delegate instance</li>
 * </ul>
 */
public <T, M extends T, D extends T> Class<? extends M> generate(Class<? extends GeneratedViewState> backingStateType, StructSchema<M> viewSchema, StructBindings<?> structBindings) {
    if (!structBindings.getImplementedViewSchemas().contains(viewSchema)) {
        throw new IllegalArgumentException(String.format("View '%s' is not supported by struct '%s'", viewSchema.getType(), structBindings.getPublicSchema().getType()));
    }
    ModelType<M> viewType = viewSchema.getType();
    StringBuilder generatedTypeNameBuilder = new StringBuilder();
    if (backingStateType == GeneratedViewState.class) {
        generatedTypeNameBuilder.append("$View");
    } else {
        generatedTypeNameBuilder.append("$NodeView");
    }
    StructSchema<D> delegateSchema = Cast.uncheckedCast(structBindings.getDelegateSchema());
    if (delegateSchema != null) {
        generatedTypeNameBuilder.append("$").append(delegateSchema.getType().getName().replaceAll("\\.", "_"));
    }
    String classNameSuffix = generatedTypeNameBuilder.toString();
    Class<?> superclass;
    final ImmutableSet.Builder<String> interfacesToImplement = ImmutableSet.builder();
    final ImmutableSet.Builder<ModelType<?>> typesToDelegate = ImmutableSet.builder();
    typesToDelegate.add(viewType);
    interfacesToImplement.add(GENERATED_VIEW_TYPE.getInternalName());
    if (backingStateType == ModelElementState.class) {
        interfacesToImplement.add(MANAGED_INSTANCE_TYPE);
    }
    Class<M> viewClass = viewType.getConcreteClass();
    if (viewClass.isInterface()) {
        superclass = Object.class;
        interfacesToImplement.add(Type.getInternalName(viewClass));
    } else {
        superclass = viewClass;
    }
    // BinaryContainer won't recognize managed binaries as BinarySpecInternal
    if (delegateSchema != null) {
        walkTypeHierarchy(delegateSchema.getType().getConcreteClass(), IGNORED_OBJECT_TYPES, new TypeVisitor<D>() {

            @Override
            public void visitType(Class<? super D> type) {
                if (type.isInterface()) {
                    typesToDelegate.add(ModelType.of(type));
                    interfacesToImplement.add(Type.getInternalName(type));
                }
            }
        });
    }
    ClassLoader targetClassLoader = viewClass.getClassLoader();
    if (delegateSchema != null) {
        // TODO - remove this once the above is removed
        try {
            viewClass.getClassLoader().loadClass(delegateSchema.getType().getConcreteClass().getName());
        } catch (ClassNotFoundException e) {
            // Delegate class is not visible to managed view type -> view type is more general than delegate type, so use the delegate classloader instead
            targetClassLoader = delegateSchema.getType().getConcreteClass().getClassLoader();
        }
    }
    AsmClassGenerator generator = new AsmClassGenerator(viewClass, classNameSuffix);
    ClassWriter visitor = generator.getVisitor();
    generateProxyClass(visitor, viewSchema, structBindings, interfacesToImplement.build(), typesToDelegate.build(), generator.getGeneratedType(), Type.getType(superclass), backingStateType);
    return generator.define(targetClassLoader);
}
Also used : AsmClassGenerator(org.gradle.model.internal.asm.AsmClassGenerator) ClassWriter(org.objectweb.asm.ClassWriter) ImmutableSet(com.google.common.collect.ImmutableSet) ModelType(org.gradle.model.internal.type.ModelType)

Example 3 with AsmClassGenerator

use of org.gradle.model.internal.asm.AsmClassGenerator in project gradle by gradle.

the class NamedObjectInstantiator method loaderFor.

private ClassGeneratingLoader loaderFor(Class<?> publicClass) {
    // 
    // Generate implementation class
    // 
    FormattingValidationProblemCollector problemCollector = new FormattingValidationProblemCollector("Named implementation class", ModelType.of(publicClass));
    visitFields(publicClass, problemCollector);
    if (problemCollector.hasProblems()) {
        throw new GradleException(problemCollector.format());
    }
    AsmClassGenerator generator = new AsmClassGenerator(publicClass, "$Impl");
    Type implementationType = generator.getGeneratedType();
    ClassWriter visitor = generator.getVisitor();
    Type publicType = Type.getType(publicClass);
    Type superClass;
    String[] interfaces;
    if (publicClass.isInterface()) {
        superClass = OBJECT;
        interfaces = new String[] { publicType.getInternalName(), MANAGED.getInternalName() };
    } else {
        superClass = publicType;
        interfaces = INTERFACES_FOR_ABSTRACT_CLASS;
    }
    visitor.visit(V1_5, ACC_PUBLIC | ACC_SYNTHETIC, implementationType.getInternalName(), null, superClass.getInternalName(), interfaces);
    // 
    // Add name field
    // 
    visitor.visitField(ACC_PRIVATE, NAME_FIELD, STRING.getDescriptor(), null, null);
    // 
    // Add constructor
    // 
    MethodVisitor methodVisitor = visitor.visitMethod(ACC_PUBLIC, CONSTRUCTOR_NAME, RETURN_VOID_FROM_STRING, null, EMPTY_STRINGS);
    methodVisitor.visitCode();
    // Call this.super()
    methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
    methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, superClass.getInternalName(), CONSTRUCTOR_NAME, RETURN_VOID, false);
    // Set this.name = param1
    methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
    methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
    methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, implementationType.getInternalName(), NAME_FIELD, STRING.getDescriptor());
    // Done
    methodVisitor.visitInsn(Opcodes.RETURN);
    methodVisitor.visitMaxs(0, 0);
    methodVisitor.visitEnd();
    // 
    // Add `getName()`
    // 
    methodVisitor = visitor.visitMethod(ACC_PUBLIC, "getName", RETURN_STRING, null, EMPTY_STRINGS);
    methodVisitor.visitCode();
    // return this.name
    methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
    methodVisitor.visitFieldInsn(Opcodes.GETFIELD, implementationType.getInternalName(), NAME_FIELD, STRING.getDescriptor());
    methodVisitor.visitInsn(Opcodes.ARETURN);
    methodVisitor.visitMaxs(0, 0);
    methodVisitor.visitEnd();
    // 
    // Add `toString()`
    // 
    methodVisitor = visitor.visitMethod(ACC_PUBLIC, "toString", RETURN_STRING, null, EMPTY_STRINGS);
    methodVisitor.visitCode();
    // return this.name
    methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
    methodVisitor.visitFieldInsn(Opcodes.GETFIELD, implementationType.getInternalName(), NAME_FIELD, STRING.getDescriptor());
    methodVisitor.visitInsn(Opcodes.ARETURN);
    methodVisitor.visitMaxs(0, 0);
    methodVisitor.visitEnd();
    visitor.visitEnd();
    generator.define();
    // 
    // Generate factory class
    // 
    generator = new AsmClassGenerator(publicClass, "$Factory");
    visitor = generator.getVisitor();
    visitor.visit(V1_5, ACC_PUBLIC | ACC_SYNTHETIC, generator.getGeneratedType().getInternalName(), null, CLASS_GENERATING_LOADER.getInternalName(), EMPTY_STRINGS);
    // 
    // Add constructor
    // 
    methodVisitor = visitor.visitMethod(ACC_PUBLIC, CONSTRUCTOR_NAME, RETURN_VOID, null, EMPTY_STRINGS);
    methodVisitor.visitCode();
    // Call this.super()
    methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
    methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, CLASS_GENERATING_LOADER.getInternalName(), CONSTRUCTOR_NAME, RETURN_VOID, false);
    // Done
    methodVisitor.visitInsn(Opcodes.RETURN);
    methodVisitor.visitMaxs(0, 0);
    methodVisitor.visitEnd();
    // 
    // Add factory method
    // 
    methodVisitor = visitor.visitMethod(ACC_PUBLIC, "load", RETURN_OBJECT_FROM_STRING, null, EMPTY_STRINGS);
    methodVisitor.visitCode();
    // Call return new <implClass>(param1)
    methodVisitor.visitTypeInsn(Opcodes.NEW, implementationType.getInternalName());
    methodVisitor.visitInsn(Opcodes.DUP);
    methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
    methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, implementationType.getInternalName(), CONSTRUCTOR_NAME, RETURN_VOID_FROM_STRING, false);
    methodVisitor.visitInsn(Opcodes.ARETURN);
    methodVisitor.visitMaxs(0, 0);
    methodVisitor.visitEnd();
    visitor.visitEnd();
    Class<Object> factoryClass = generator.define();
    try {
        return (ClassGeneratingLoader) (factoryClass.newInstance());
    } catch (Exception e) {
        throw UncheckedException.throwAsUncheckedException(e);
    }
}
Also used : Type(org.objectweb.asm.Type) ModelType(org.gradle.model.internal.type.ModelType) GradleException(org.gradle.api.GradleException) FormattingValidationProblemCollector(org.gradle.model.internal.inspect.FormattingValidationProblemCollector) GroovyObject(groovy.lang.GroovyObject) AsmClassGenerator(org.gradle.model.internal.asm.AsmClassGenerator) ClassWriter(org.objectweb.asm.ClassWriter) ObjectInstantiationException(org.gradle.api.reflect.ObjectInstantiationException) UncheckedException(org.gradle.internal.UncheckedException) GradleException(org.gradle.api.GradleException) UncheckedExecutionException(com.google.common.util.concurrent.UncheckedExecutionException) MethodVisitor(org.objectweb.asm.MethodVisitor)

Aggregations

AsmClassGenerator (org.gradle.model.internal.asm.AsmClassGenerator)3 ClassWriter (org.objectweb.asm.ClassWriter)3 ModelType (org.gradle.model.internal.type.ModelType)2 Type (org.objectweb.asm.Type)2 ImmutableSet (com.google.common.collect.ImmutableSet)1 UncheckedExecutionException (com.google.common.util.concurrent.UncheckedExecutionException)1 GroovyObject (groovy.lang.GroovyObject)1 GradleException (org.gradle.api.GradleException)1 ObjectInstantiationException (org.gradle.api.reflect.ObjectInstantiationException)1 UncheckedException (org.gradle.internal.UncheckedException)1 FormattingValidationProblemCollector (org.gradle.model.internal.inspect.FormattingValidationProblemCollector)1 MethodVisitor (org.objectweb.asm.MethodVisitor)1