io.micronaut.inject.writer.ExecutableMethodWriter Maven / Gradle / Ivy
/*
* Copyright 2017-2020 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.inject.writer;
import io.micronaut.context.AbstractExecutableMethod;
import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.reflect.ReflectionUtils;
import io.micronaut.core.type.Argument;
import io.micronaut.inject.ExecutableMethod;
import io.micronaut.inject.annotation.AnnotationMetadataReference;
import io.micronaut.inject.annotation.DefaultAnnotationMetadata;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
/**
* Writes out {@link io.micronaut.inject.ExecutableMethod} implementations.
*
* @author Graeme Rocher
* @since 1.0
*/
@Internal
public class ExecutableMethodWriter extends AbstractAnnotationMetadataWriter implements Opcodes {
/**
* Constant for parent field.
*/
public static final String FIELD_PARENT = "$parent";
protected static final org.objectweb.asm.commons.Method METHOD_INVOKE_INTERNAL = org.objectweb.asm.commons.Method.getMethod(
ReflectionUtils.getRequiredInternalMethod(AbstractExecutableMethod.class, "invokeInternal", Object.class, Object[].class));
protected static final org.objectweb.asm.commons.Method METHOD_IS_ABSTRACT = org.objectweb.asm.commons.Method.getMethod(
ReflectionUtils.getRequiredInternalMethod(ExecutableMethod.class, "isAbstract"));
protected static final org.objectweb.asm.commons.Method METHOD_IS_SUSPEND = org.objectweb.asm.commons.Method.getMethod(
ReflectionUtils.getRequiredInternalMethod(ExecutableMethod.class, "isSuspend"));
protected static final Method METHOD_GET_TARGET = Method.getMethod("java.lang.reflect.Method resolveTargetMethod()");
private static final Type TYPE_REFLECTION_UTILS = Type.getType(ReflectionUtils.class);
private static final org.objectweb.asm.commons.Method METHOD_GET_REQUIRED_METHOD = org.objectweb.asm.commons.Method.getMethod(
ReflectionUtils.getRequiredInternalMethod(ReflectionUtils.class, "getRequiredMethod", Class.class, String.class, Class[].class));
protected final Type methodType;
private final ClassWriter classWriter;
private final String className;
private final String internalName;
private final String beanFullClassName;
private final String methodProxyShortName;
private final boolean isInterface;
private final boolean isAbstract;
private final boolean isSuspend;
private String outerClassName = null;
private boolean isStatic = false;
/**
* @param beanFullClassName The bean full class name
* @param methodClassName The method class name
* @param methodProxyShortName The method proxy short name
* @param isInterface Whether is an interface
* @param isSuspend Whether the method is Kotlin suspend function
* @param annotationMetadata The annotation metadata
*/
public ExecutableMethodWriter(
String beanFullClassName,
String methodClassName,
String methodProxyShortName,
boolean isInterface,
boolean isSuspend,
AnnotationMetadata annotationMetadata) {
super(methodClassName, annotationMetadata, true);
this.classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
this.beanFullClassName = beanFullClassName;
this.methodProxyShortName = methodProxyShortName;
this.className = methodClassName;
this.internalName = getInternalName(methodClassName);
this.methodType = getObjectType(methodClassName);
this.isInterface = isInterface;
this.isAbstract = isInterface;
this.isSuspend = isSuspend;
}
/**
* @param beanFullClassName The bean full class name
* @param methodClassName The method class name
* @param methodProxyShortName The method proxy short name
* @param isInterface Whether is an interface
* @param isAbstract Whether the method is abstract
* @param isSuspend Whether the method is Kotlin suspend function
* @param annotationMetadata The annotation metadata
*/
public ExecutableMethodWriter(
String beanFullClassName,
String methodClassName,
String methodProxyShortName,
boolean isInterface,
boolean isAbstract,
boolean isSuspend,
AnnotationMetadata annotationMetadata) {
super(methodClassName, annotationMetadata, true);
this.classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
this.beanFullClassName = beanFullClassName;
this.methodProxyShortName = methodProxyShortName;
this.className = methodClassName;
this.internalName = getInternalName(methodClassName);
this.methodType = getObjectType(methodClassName);
this.isInterface = isInterface;
this.isAbstract = isInterface || isAbstract;
this.isSuspend = isSuspend;
}
/**
* @return Is the method abstract.
*/
public boolean isAbstract() {
return isAbstract;
}
/**
* @return Is the method suspend.
*/
public boolean isSuspend() {
return isSuspend;
}
/**
* @return The class name
*/
public String getClassName() {
return className;
}
/**
* @return The internal name
*/
public String getInternalName() {
return internalName;
}
/**
* @param outerName The outer name
* @param outerClassWriter The outer class writer
*/
public void makeInner(String outerName, ClassWriter outerClassWriter) {
outerClassWriter.visitInnerClass(internalName, getInternalName(outerName), methodProxyShortName.substring(1), 0);
classWriter.visitOuterClass(getInternalName(outerName), null, null);
if (!isStatic) {
classWriter.visitField(ACC_PRIVATE | ACC_FINAL, FIELD_PARENT, getTypeDescriptor(outerName), null, null);
}
this.outerClassName = outerName;
}
/**
* Write the method.
* @param declaringType The declaring type
* @param returnType The return type
* @param genericReturnType The generic return type
* @param returnTypeGenericTypes The return type generics
* @param methodName The method name
* @param argumentTypes The argument types
* @param genericArgumentTypes The generic argument types
* @param argumentAnnotationMetadata The argument annotation metadata
* @param genericTypes The generic types
*/
public void visitMethod(Object declaringType,
Object returnType,
Object genericReturnType,
Map returnTypeGenericTypes,
String methodName,
Map argumentTypes,
Map genericArgumentTypes,
Map argumentAnnotationMetadata,
Map> genericTypes) {
Type declaringTypeObject = getTypeReference(declaringType);
boolean hasArgs = !argumentTypes.isEmpty();
Collection
© 2015 - 2025 Weber Informatics LLC | Privacy Policy