Search in sources :

Example 1 with AbstractConstructorInjectionPoint

use of io.micronaut.context.AbstractConstructorInjectionPoint in project micronaut-core by micronaut-projects.

the class BeanDefinitionWriter method initInterceptedConstructorWriter.

private int initInterceptedConstructorWriter(GeneratorAdapter buildMethodVisitor, List<ParameterElement> parameters, @Nullable FactoryMethodDef factoryMethodDef) {
    // write the constructor that is a subclass of AbstractConstructorInjectionPoint
    InnerClassDef constructorInjectionPointInnerClass = newInnerClass(AbstractConstructorInjectionPoint.class);
    final ClassWriter interceptedConstructorWriter = constructorInjectionPointInnerClass.innerClassWriter;
    org.objectweb.asm.commons.Method constructorMethod = org.objectweb.asm.commons.Method.getMethod(CONSTRUCTOR_ABSTRACT_CONSTRUCTOR_IP);
    GeneratorAdapter protectedConstructor;
    final boolean hasFactoryMethod = factoryMethodDef != null;
    final String interceptedConstructorDescriptor;
    final Type factoryType = hasFactoryMethod ? factoryMethodDef.factoryType : null;
    final String factoryFieldName = "$factory";
    if (hasFactoryMethod) {
        // for factory methods we have to store the factory instance in a field and modify the constructor pass the factory instance
        newFinalField(interceptedConstructorWriter, factoryType, factoryFieldName);
        interceptedConstructorDescriptor = getConstructorDescriptor(new Type[] { TYPE_BEAN_DEFINITION, factoryType });
        protectedConstructor = new GeneratorAdapter(interceptedConstructorWriter.visitMethod(ACC_PROTECTED, CONSTRUCTOR_NAME, interceptedConstructorDescriptor, null, null), ACC_PROTECTED, CONSTRUCTOR_NAME, interceptedConstructorDescriptor);
    } else {
        interceptedConstructorDescriptor = constructorMethod.getDescriptor();
        protectedConstructor = new GeneratorAdapter(interceptedConstructorWriter.visitMethod(ACC_PROTECTED, CONSTRUCTOR_NAME, interceptedConstructorDescriptor, null, null), ACC_PROTECTED, CONSTRUCTOR_NAME, interceptedConstructorDescriptor);
    }
    if (hasFactoryMethod) {
        protectedConstructor.loadThis();
        protectedConstructor.loadArg(1);
        protectedConstructor.putField(constructorInjectionPointInnerClass.innerClassType, factoryFieldName, factoryType);
    }
    protectedConstructor.loadThis();
    protectedConstructor.loadArg(0);
    protectedConstructor.invokeConstructor(Type.getType(AbstractConstructorInjectionPoint.class), constructorMethod);
    protectedConstructor.returnValue();
    protectedConstructor.visitMaxs(1, 1);
    protectedConstructor.visitEnd();
    // now we need to implement the invoke method to execute the actual instantiation
    final GeneratorAdapter invokeMethod = startPublicMethod(interceptedConstructorWriter, METHOD_INVOKE_CONSTRUCTOR);
    if (hasFactoryMethod) {
        invokeMethod.loadThis();
        invokeMethod.getField(constructorInjectionPointInnerClass.innerClassType, factoryFieldName, factoryType);
        pushCastToType(invokeMethod, factoryType);
    } else {
        invokeMethod.visitTypeInsn(NEW, beanType.getInternalName());
        invokeMethod.visitInsn(DUP);
    }
    for (int i = 0; i < parameters.size(); i++) {
        invokeMethod.loadArg(0);
        invokeMethod.push(i);
        invokeMethod.arrayLoad(TYPE_OBJECT);
        pushCastToType(invokeMethod, parameters.get(i));
    }
    if (hasFactoryMethod) {
        if (factoryMethodDef.factoryMethod instanceof MethodElement) {
            invokeMethod.visitMethodInsn(INVOKEVIRTUAL, factoryType.getInternalName(), factoryMethodDef.factoryMethod.getName(), factoryMethodDef.methodDescriptor, false);
        } else {
            invokeMethod.getField(factoryType, factoryMethodDef.factoryMethod.getName(), beanType);
        }
    } else {
        String constructorDescriptor = getConstructorDescriptor(parameters);
        invokeMethod.visitMethodInsn(INVOKESPECIAL, beanType.getInternalName(), "<init>", constructorDescriptor, false);
    }
    invokeMethod.returnValue();
    invokeMethod.visitMaxs(1, 1);
    invokeMethod.visitEnd();
    // instantiate a new instance and return
    buildMethodVisitor.visitTypeInsn(NEW, constructorInjectionPointInnerClass.constructorInternalName);
    buildMethodVisitor.visitInsn(DUP);
    // pass outer class instance to constructor
    buildMethodVisitor.loadThis();
    if (hasFactoryMethod) {
        buildMethodVisitor.loadLocal(factoryMethodDef.factoryVar);
        pushCastToType(buildMethodVisitor, factoryType);
    }
    buildMethodVisitor.visitMethodInsn(INVOKESPECIAL, constructorInjectionPointInnerClass.constructorInternalName, "<init>", interceptedConstructorDescriptor, false);
    final int constructorIndex = buildMethodVisitor.newLocal(Type.getType(AbstractConstructorInjectionPoint.class));
    buildMethodVisitor.storeLocal(constructorIndex);
    return constructorIndex;
}
Also used : AbstractConstructorInjectionPoint(io.micronaut.context.AbstractConstructorInjectionPoint) Type(org.objectweb.asm.Type) AdvisedBeanType(io.micronaut.inject.AdvisedBeanType) MethodElement(io.micronaut.inject.ast.MethodElement) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) ClassWriter(org.objectweb.asm.ClassWriter) AbstractConstructorInjectionPoint(io.micronaut.context.AbstractConstructorInjectionPoint) ConstructorInjectionPoint(io.micronaut.inject.ConstructorInjectionPoint)

Aggregations

AbstractConstructorInjectionPoint (io.micronaut.context.AbstractConstructorInjectionPoint)1 AdvisedBeanType (io.micronaut.inject.AdvisedBeanType)1 ConstructorInjectionPoint (io.micronaut.inject.ConstructorInjectionPoint)1 MethodElement (io.micronaut.inject.ast.MethodElement)1 ClassWriter (org.objectweb.asm.ClassWriter)1 Type (org.objectweb.asm.Type)1 GeneratorAdapter (org.objectweb.asm.commons.GeneratorAdapter)1