Search in sources :

Example 1 with TypedElement

use of io.micronaut.inject.ast.TypedElement in project micronaut-core by micronaut-projects.

the class BeanDefinitionWriter method visitMethodInjectionPointInternal.

private void visitMethodInjectionPointInternal(MethodVisitData methodVisitData, GeneratorAdapter injectMethodVisitor, int injectInstanceIndex) {
    MethodElement methodElement = methodVisitData.getMethodElement();
    final AnnotationMetadata annotationMetadata = methodElement.getAnnotationMetadata();
    final List<ParameterElement> argumentTypes = Arrays.asList(methodElement.getParameters());
    applyDefaultNamedToParameters(argumentTypes);
    final TypedElement declaringType = methodVisitData.beanType;
    final String methodName = methodElement.getName();
    final boolean requiresReflection = methodVisitData.requiresReflection;
    final ClassElement returnType = methodElement.getReturnType();
    DefaultAnnotationMetadata.contributeDefaults(this.annotationMetadata, annotationMetadata);
    DefaultAnnotationMetadata.contributeRepeatable(this.annotationMetadata, returnType);
    boolean hasArguments = methodElement.hasParameters();
    int argCount = hasArguments ? argumentTypes.size() : 0;
    Type declaringTypeRef = JavaModelUtils.getTypeReference(declaringType);
    boolean hasInjectScope = false;
    for (ParameterElement value : argumentTypes) {
        DefaultAnnotationMetadata.contributeDefaults(this.annotationMetadata, value.getAnnotationMetadata());
        DefaultAnnotationMetadata.contributeRepeatable(this.annotationMetadata, value.getGenericType());
        if (value.hasDeclaredAnnotation(InjectScope.class)) {
            hasInjectScope = true;
        }
    }
    if (!requiresReflection) {
        // if the method doesn't require reflection then invoke it directly
        // invoke the method on this injected instance
        injectMethodVisitor.loadLocal(injectInstanceIndex, beanType);
        String methodDescriptor;
        if (hasArguments) {
            methodDescriptor = getMethodDescriptor(returnType, argumentTypes);
            Iterator<ParameterElement> argIterator = argumentTypes.iterator();
            for (int i = 0; i < argCount; i++) {
                ParameterElement entry = argIterator.next();
                pushMethodParameterValue(injectMethodVisitor, i, entry);
            }
        } else {
            methodDescriptor = getMethodDescriptor(returnType, Collections.emptyList());
        }
        injectMethodVisitor.visitMethodInsn(isInterface ? INVOKEINTERFACE : INVOKEVIRTUAL, declaringTypeRef.getInternalName(), methodName, methodDescriptor, isInterface);
        if (isConfigurationProperties && returnType != PrimitiveElement.VOID) {
            injectMethodVisitor.pop();
        }
    } else {
        injectMethodVisitor.loadThis();
        injectMethodVisitor.loadArg(0);
        injectMethodVisitor.loadArg(1);
        injectMethodVisitor.push(currentMethodIndex);
        injectMethodVisitor.loadLocal(injectInstanceLocalVarIndex, beanType);
        if (hasArguments) {
            pushNewArray(injectMethodVisitor, Object.class, argumentTypes.size());
            Iterator<ParameterElement> argIterator = argumentTypes.iterator();
            for (int i = 0; i < argCount; i++) {
                int finalI = i;
                pushStoreInArray(injectMethodVisitor, i, argumentTypes.size(), () -> {
                    ParameterElement entry = argIterator.next();
                    pushMethodParameterValue(injectMethodVisitor, finalI, entry);
                    pushBoxPrimitiveIfNecessary(entry.getType(), injectMethodVisitor);
                });
            }
        } else {
            pushNewArray(injectMethodVisitor, Object.class, 0);
        }
        injectMethodVisitor.invokeVirtual(superType, INVOKE_WITH_REFLECTION_METHOD);
    }
    destroyInjectScopeBeansIfNecessary(injectMethodVisitor, hasInjectScope);
}
Also used : Type(org.objectweb.asm.Type) AdvisedBeanType(io.micronaut.inject.AdvisedBeanType) TypedElement(io.micronaut.inject.ast.TypedElement) MethodElement(io.micronaut.inject.ast.MethodElement) ClassElement(io.micronaut.inject.ast.ClassElement) ParameterElement(io.micronaut.inject.ast.ParameterElement) MutableAnnotationMetadata(io.micronaut.inject.annotation.MutableAnnotationMetadata) DefaultAnnotationMetadata(io.micronaut.inject.annotation.DefaultAnnotationMetadata) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) AbstractConstructorInjectionPoint(io.micronaut.context.AbstractConstructorInjectionPoint) ConstructorInjectionPoint(io.micronaut.inject.ConstructorInjectionPoint)

Example 2 with TypedElement

use of io.micronaut.inject.ast.TypedElement in project micronaut-core by micronaut-projects.

the class AopProxyWriter method visitAroundMethod.

/**
 * Visit a method that is to be proxied.
 *
 * @param beanType      The bean type.
 * @param methodElement The method element
 */
public void visitAroundMethod(TypedElement beanType, MethodElement methodElement) {
    ClassElement returnType = methodElement.isSuspend() ? ClassElement.of(Object.class) : methodElement.getReturnType();
    Type returnTypeObject = JavaModelUtils.getTypeReference(returnType);
    boolean isPrimitive = returnType.isPrimitive();
    boolean isVoidReturn = isPrimitive && returnTypeObject.equals(Type.VOID_TYPE);
    final Optional<MethodElement> overridden = methodElement.getOwningType().getEnclosedElement(ElementQuery.ALL_METHODS.onlyInstance().named(name -> name.equals(methodElement.getName())).filter(el -> el.overrides(methodElement)));
    if (overridden.isPresent()) {
        MethodElement overriddenBy = overridden.get();
        String methodElementKey = methodElement.getName() + Arrays.stream(methodElement.getSuspendParameters()).map(p -> p.getType().getName()).collect(Collectors.joining(","));
        String overriddenByKey = overriddenBy.getName() + Arrays.stream(methodElement.getSuspendParameters()).map(p -> p.getGenericType().getName()).collect(Collectors.joining(","));
        if (!methodElementKey.equals(overriddenByKey)) {
            buildMethodDelegate(methodElement, overriddenBy, isVoidReturn);
            return;
        }
    }
    String methodName = methodElement.getName();
    List<ParameterElement> argumentTypeList = Arrays.asList(methodElement.getSuspendParameters());
    int argumentCount = argumentTypeList.size();
    final Type declaringTypeReference = JavaModelUtils.getTypeReference(beanType);
    MethodRef methodKey = new MethodRef(methodName, argumentTypeList, returnTypeObject);
    if (!proxiedMethodsRefSet.contains(methodKey)) {
        String interceptedProxyClassName = null;
        String interceptedProxyBridgeMethodName = null;
        if (!isProxyTarget) {
            if (!methodElement.isAbstract() || methodElement.isDefault()) {
                interceptedProxyClassName = proxyFullName;
                interceptedProxyBridgeMethodName = "$$access$$" + methodName;
                String bridgeDesc = getMethodDescriptor(returnType, argumentTypeList);
                // now build a bridge to invoke the original method
                MethodVisitor bridgeWriter = classWriter.visitMethod(ACC_SYNTHETIC, interceptedProxyBridgeMethodName, bridgeDesc, null, null);
                GeneratorAdapter bridgeGenerator = new GeneratorAdapter(bridgeWriter, ACC_SYNTHETIC, interceptedProxyBridgeMethodName, bridgeDesc);
                bridgeGenerator.loadThis();
                for (int i = 0; i < argumentTypeList.size(); i++) {
                    bridgeGenerator.loadArg(i);
                }
                String desc = getMethodDescriptor(returnType, argumentTypeList);
                bridgeWriter.visitMethodInsn(INVOKESPECIAL, declaringTypeReference.getInternalName(), methodName, desc, this.isInterface && methodElement.isDefault());
                pushReturnValue(bridgeWriter, returnType);
                bridgeWriter.visitMaxs(DEFAULT_MAX_STACK, 1);
                bridgeWriter.visitEnd();
            }
        }
        BeanDefinitionWriter beanDefinitionWriter = parentWriter == null ? proxyBeanDefinitionWriter : parentWriter;
        int methodIndex = beanDefinitionWriter.visitExecutableMethod(beanType, methodElement, interceptedProxyClassName, interceptedProxyBridgeMethodName);
        int index = proxyMethodCount++;
        methodKey.methodIndex = methodIndex;
        proxiedMethods.add(methodKey);
        proxiedMethodsRefSet.add(methodKey);
        proxyTargetMethods.add(methodKey);
        buildMethodOverride(returnType, methodName, index, argumentTypeList, argumentCount, isVoidReturn);
    }
}
Also used : ElementQuery(io.micronaut.inject.ast.ElementQuery) Arrays(java.util.Arrays) InterceptedProxy(io.micronaut.aop.InterceptedProxy) MethodVisitor(org.objectweb.asm.MethodVisitor) BeanContext(io.micronaut.context.BeanContext) ArrayUtils(io.micronaut.core.util.ArrayUtils) FieldElement(io.micronaut.inject.ast.FieldElement) DefaultBeanContext(io.micronaut.context.DefaultBeanContext) Type(org.objectweb.asm.Type) ProxyingBeanDefinitionVisitor(io.micronaut.inject.writer.ProxyingBeanDefinitionVisitor) Introduced(io.micronaut.aop.Introduced) MethodInterceptorChain(io.micronaut.aop.chain.MethodInterceptorChain) Map(java.util.Map) BeanResolutionContext(io.micronaut.context.BeanResolutionContext) AbstractClassFileWriter(io.micronaut.inject.writer.AbstractClassFileWriter) HotSwappableInterceptedProxy(io.micronaut.aop.HotSwappableInterceptedProxy) BeanLocator(io.micronaut.context.BeanLocator) ClassVisitor(org.objectweb.asm.ClassVisitor) ReadWriteLock(java.util.concurrent.locks.ReadWriteLock) Set(java.util.Set) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) StringUtils(io.micronaut.core.util.StringUtils) List(java.util.List) Interceptor(io.micronaut.aop.Interceptor) AnnotationUtil(io.micronaut.core.annotation.AnnotationUtil) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) ProxyBeanDefinition(io.micronaut.inject.ProxyBeanDefinition) MethodElement(io.micronaut.inject.ast.MethodElement) Optional(java.util.Optional) InterceptorChain(io.micronaut.aop.chain.InterceptorChain) BeanDefinitionWriter(io.micronaut.inject.writer.BeanDefinitionWriter) ConfigurationMetadata(io.micronaut.inject.configuration.ConfigurationMetadata) JavaModelUtils(io.micronaut.inject.processing.JavaModelUtils) ClassWriter(org.objectweb.asm.ClassWriter) BeanRegistration(io.micronaut.context.BeanRegistration) OriginatingElements(io.micronaut.inject.writer.OriginatingElements) Qualifier(io.micronaut.context.Qualifier) Label(org.objectweb.asm.Label) ClassElement(io.micronaut.inject.ast.ClassElement) ReentrantReadWriteLock(java.util.concurrent.locks.ReentrantReadWriteLock) Toggleable(io.micronaut.core.util.Toggleable) DefaultAnnotationMetadata(io.micronaut.inject.annotation.DefaultAnnotationMetadata) Constructor(java.lang.reflect.Constructor) ExecutableMethod(io.micronaut.inject.ExecutableMethod) ParameterElement(io.micronaut.inject.ast.ParameterElement) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Method(org.objectweb.asm.commons.Method) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) TypedElement(io.micronaut.inject.ast.TypedElement) AnnotationMetadataReference(io.micronaut.inject.annotation.AnnotationMetadataReference) ConfigurationReader(io.micronaut.context.annotation.ConfigurationReader) Argument(io.micronaut.core.type.Argument) ClassWriterOutputVisitor(io.micronaut.inject.writer.ClassWriterOutputVisitor) LinkedHashSet(java.util.LinkedHashSet) ExecutableMethodsDefinitionWriter(io.micronaut.inject.writer.ExecutableMethodsDefinitionWriter) OutputStream(java.io.OutputStream) Opcodes(org.objectweb.asm.Opcodes) Element(io.micronaut.inject.ast.Element) Iterator(java.util.Iterator) InterceptedMethodUtil(io.micronaut.aop.internal.intercepted.InterceptedMethodUtil) IOException(java.io.IOException) OptionalValues(io.micronaut.core.value.OptionalValues) ReflectionUtils(io.micronaut.core.reflect.ReflectionUtils) File(java.io.File) InterceptorKind(io.micronaut.aop.InterceptorKind) NonNull(io.micronaut.core.annotation.NonNull) ExecutionHandleLocator(io.micronaut.context.ExecutionHandleLocator) VisitorContext(io.micronaut.inject.visitor.VisitorContext) Lock(java.util.concurrent.locks.Lock) ConfigurationMetadataBuilder(io.micronaut.inject.configuration.ConfigurationMetadataBuilder) BeanDefinitionVisitor(io.micronaut.inject.writer.BeanDefinitionVisitor) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) BeanDefinition(io.micronaut.inject.BeanDefinition) Collections(java.util.Collections) Intercepted(io.micronaut.aop.Intercepted) MethodElement(io.micronaut.inject.ast.MethodElement) ClassElement(io.micronaut.inject.ast.ClassElement) BeanDefinitionWriter(io.micronaut.inject.writer.BeanDefinitionWriter) MethodVisitor(org.objectweb.asm.MethodVisitor) Type(org.objectweb.asm.Type) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) ParameterElement(io.micronaut.inject.ast.ParameterElement)

Example 3 with TypedElement

use of io.micronaut.inject.ast.TypedElement in project micronaut-core by micronaut-projects.

the class BeanIntrospectionWriter method visitProperty.

/**
 * Visit a property.
 *
 * @param type               The property type
 * @param genericType        The generic type
 * @param name               The property name
 * @param readMethod         The read method
 * @param writeMethod        The write methodname
 * @param isReadOnly         Is the property read only
 * @param annotationMetadata The property annotation metadata
 * @param typeArguments      The type arguments
 */
void visitProperty(@NonNull TypedElement type, @NonNull TypedElement genericType, @NonNull String name, @Nullable MethodElement readMethod, @Nullable MethodElement writeMethod, boolean isReadOnly, @Nullable AnnotationMetadata annotationMetadata, @Nullable Map<String, ClassElement> typeArguments) {
    DefaultAnnotationMetadata.contributeDefaults(this.annotationMetadata, annotationMetadata);
    if (typeArguments != null) {
        for (ClassElement element : typeArguments.values()) {
            DefaultAnnotationMetadata.contributeRepeatable(this.annotationMetadata, element);
        }
    }
    int readMethodIndex = -1;
    if (readMethod != null) {
        readMethodIndex = dispatchWriter.addMethod(classElement, readMethod, true);
    }
    int writeMethodIndex = -1;
    int withMethodIndex = -1;
    if (writeMethod != null) {
        writeMethodIndex = dispatchWriter.addMethod(classElement, writeMethod, true);
    }
    boolean isMutable = !isReadOnly || hasAssociatedConstructorArgument(name, genericType);
    if (isMutable) {
        if (writeMethod == null) {
            final String prefix = this.annotationMetadata.stringValue(Introspected.class, "withPrefix").orElse("with");
            ElementQuery<MethodElement> elementQuery = ElementQuery.of(MethodElement.class).onlyAccessible().onlyDeclared().onlyInstance().named((n) -> n.startsWith(prefix) && n.equals(prefix + NameUtils.capitalize(name))).filter((methodElement -> {
                ParameterElement[] parameters = methodElement.getParameters();
                return parameters.length == 1 && methodElement.getGenericReturnType().getName().equals(classElement.getName()) && type.getType().isAssignable(parameters[0].getType());
            }));
            MethodElement withMethod = classElement.getEnclosedElement(elementQuery).orElse(null);
            if (withMethod != null) {
                withMethodIndex = dispatchWriter.addMethod(classElement, withMethod, true);
            } else {
                MethodElement constructor = this.constructor == null ? defaultConstructor : this.constructor;
                if (constructor != null) {
                    withMethodIndex = dispatchWriter.addDispatchTarget(new CopyConstructorDispatchTarget(constructor, name));
                }
            }
        }
    // Otherwise, set method would be used in BeanProperty
    } else {
        withMethodIndex = dispatchWriter.addDispatchTarget(new ExceptionDispatchTarget(UnsupportedOperationException.class, "Cannot mutate property [" + name + "] that is not mutable via a setter method or constructor argument for type: " + beanType.getClassName()));
    }
    beanProperties.add(new BeanPropertyData(genericType, name, annotationMetadata, typeArguments, readMethodIndex, writeMethodIndex, withMethodIndex, isReadOnly));
}
Also used : ElementQuery(io.micronaut.inject.ast.ElementQuery) Arrays(java.util.Arrays) ArrayUtils(io.micronaut.core.util.ArrayUtils) FieldElement(io.micronaut.inject.ast.FieldElement) Internal(io.micronaut.core.annotation.Internal) BeanIntrospectionReference(io.micronaut.core.beans.BeanIntrospectionReference) Type(org.objectweb.asm.Type) Map(java.util.Map) NameUtils(io.micronaut.core.naming.NameUtils) AbstractBeanIntrospectionReference(io.micronaut.core.beans.AbstractBeanIntrospectionReference) AbstractAnnotationMetadataWriter(io.micronaut.inject.writer.AbstractAnnotationMetadataWriter) AnnotationMetadataWriter(io.micronaut.inject.annotation.AnnotationMetadataWriter) AnnotationMetadataHierarchy(io.micronaut.inject.annotation.AnnotationMetadataHierarchy) Collection(java.util.Collection) Set(java.util.Set) NotNull(javax.validation.constraints.NotNull) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Introspected(io.micronaut.core.annotation.Introspected) List(java.util.List) MethodElement(io.micronaut.inject.ast.MethodElement) JavaModelUtils(io.micronaut.inject.processing.JavaModelUtils) ClassWriter(org.objectweb.asm.ClassWriter) AbstractInitializableBeanIntrospection(io.micronaut.inject.beans.AbstractInitializableBeanIntrospection) Label(org.objectweb.asm.Label) ClassElement(io.micronaut.inject.ast.ClassElement) HashMap(java.util.HashMap) StringSwitchWriter(io.micronaut.inject.writer.StringSwitchWriter) DefaultAnnotationMetadata(io.micronaut.inject.annotation.DefaultAnnotationMetadata) ConstructorElement(io.micronaut.inject.ast.ConstructorElement) ParameterElement(io.micronaut.inject.ast.ParameterElement) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Method(org.objectweb.asm.commons.Method) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) TypedElement(io.micronaut.inject.ast.TypedElement) Nullable(io.micronaut.core.annotation.Nullable) AnnotationMetadataReference(io.micronaut.inject.annotation.AnnotationMetadataReference) BiConsumer(java.util.function.BiConsumer) Argument(io.micronaut.core.type.Argument) ClassWriterOutputVisitor(io.micronaut.inject.writer.ClassWriterOutputVisitor) LinkedHashSet(java.util.LinkedHashSet) OutputStream(java.io.OutputStream) Opcodes(org.objectweb.asm.Opcodes) IOException(java.io.IOException) ReflectionUtils(io.micronaut.core.reflect.ReflectionUtils) NonNull(io.micronaut.core.annotation.NonNull) DispatchWriter(io.micronaut.inject.writer.DispatchWriter) BeanIntrospection(io.micronaut.core.beans.BeanIntrospection) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) Collections(java.util.Collections) Introspected(io.micronaut.core.annotation.Introspected) MethodElement(io.micronaut.inject.ast.MethodElement) ClassElement(io.micronaut.inject.ast.ClassElement)

Example 4 with TypedElement

use of io.micronaut.inject.ast.TypedElement in project micronaut-core by micronaut-projects.

the class AbstractClassFileWriter method getMethodDescriptorForReturnType.

/**
 * @param returnType    The return type
 * @param argumentTypes The argument types
 * @return The method descriptor
 */
protected static String getMethodDescriptorForReturnType(Type returnType, Collection<? extends TypedElement> argumentTypes) {
    StringBuilder builder = new StringBuilder();
    builder.append('(');
    for (TypedElement argumentType : argumentTypes) {
        builder.append(getTypeDescriptor(argumentType));
    }
    builder.append(')');
    builder.append(returnType.getDescriptor());
    return builder.toString();
}
Also used : TypedElement(io.micronaut.inject.ast.TypedElement)

Example 5 with TypedElement

use of io.micronaut.inject.ast.TypedElement in project micronaut-core by micronaut-projects.

the class AbstractClassFileWriter method getMethodDescriptor.

/**
 * @param returnType    The return type
 * @param argumentTypes The argument types
 * @return The method descriptor
 */
protected static String getMethodDescriptor(TypedElement returnType, Collection<? extends TypedElement> argumentTypes) {
    StringBuilder builder = new StringBuilder();
    builder.append('(');
    for (TypedElement argumentType : argumentTypes) {
        builder.append(getTypeDescriptor(argumentType));
    }
    builder.append(')');
    builder.append(getTypeDescriptor(returnType));
    return builder.toString();
}
Also used : TypedElement(io.micronaut.inject.ast.TypedElement)

Aggregations

TypedElement (io.micronaut.inject.ast.TypedElement)5 AnnotationMetadata (io.micronaut.core.annotation.AnnotationMetadata)3 DefaultAnnotationMetadata (io.micronaut.inject.annotation.DefaultAnnotationMetadata)3 ClassElement (io.micronaut.inject.ast.ClassElement)3 MethodElement (io.micronaut.inject.ast.MethodElement)3 ParameterElement (io.micronaut.inject.ast.ParameterElement)3 Type (org.objectweb.asm.Type)3 NonNull (io.micronaut.core.annotation.NonNull)2 ReflectionUtils (io.micronaut.core.reflect.ReflectionUtils)2 Argument (io.micronaut.core.type.Argument)2 ArrayUtils (io.micronaut.core.util.ArrayUtils)2 AnnotationMetadataReference (io.micronaut.inject.annotation.AnnotationMetadataReference)2 ElementQuery (io.micronaut.inject.ast.ElementQuery)2 FieldElement (io.micronaut.inject.ast.FieldElement)2 JavaModelUtils (io.micronaut.inject.processing.JavaModelUtils)2 ClassWriterOutputVisitor (io.micronaut.inject.writer.ClassWriterOutputVisitor)2 IOException (java.io.IOException)2 OutputStream (java.io.OutputStream)2 ArrayList (java.util.ArrayList)2 Arrays (java.util.Arrays)2