use of io.micronaut.inject.ast.ParameterElement in project micronaut-core by micronaut-projects.
the class AopProxyWriter method visitBeanDefinitionEnd.
/**
* Finalizes the proxy. This method should be called before writing the proxy to disk with {@link #writeTo(File)}
*/
@Override
public void visitBeanDefinitionEnd() {
if (declaredConstructor == null) {
throw new IllegalStateException("The method visitBeanDefinitionConstructor(..) should be called at least once");
} else {
initConstructor(declaredConstructor);
}
if (parentWriter != null && !isProxyTarget) {
processAlreadyVisitedMethods(parentWriter);
}
interceptorParameter.annotate(AnnotationUtil.ANN_INTERCEPTOR_BINDING_QUALIFIER, builder -> {
final AnnotationValue<?>[] interceptorBinding = this.interceptorBinding.toArray(new AnnotationValue[0]);
builder.values(interceptorBinding);
});
qualifierParameter.annotate(AnnotationUtil.NULLABLE);
String constructorDescriptor = getConstructorDescriptor(Arrays.asList(newConstructor.getParameters()));
ClassWriter proxyClassWriter = this.classWriter;
this.constructorWriter = proxyClassWriter.visitMethod(ACC_PUBLIC, CONSTRUCTOR_NAME, constructorDescriptor, null, null);
this.constructorGenerator = new GeneratorAdapter(constructorWriter, Opcodes.ACC_PUBLIC, CONSTRUCTOR_NAME, constructorDescriptor);
GeneratorAdapter proxyConstructorGenerator = this.constructorGenerator;
proxyConstructorGenerator.loadThis();
if (isInterface) {
proxyConstructorGenerator.invokeConstructor(TYPE_OBJECT, METHOD_DEFAULT_CONSTRUCTOR);
} else {
ParameterElement[] existingArguments = declaredConstructor.getParameters();
for (int i = 0; i < existingArguments.length; i++) {
proxyConstructorGenerator.loadArg(i);
}
String superConstructorDescriptor = getConstructorDescriptor(Arrays.asList(existingArguments));
proxyConstructorGenerator.invokeConstructor(getTypeReferenceForName(targetClassFullName), new Method(CONSTRUCTOR_NAME, superConstructorDescriptor));
}
proxyBeanDefinitionWriter.visitBeanDefinitionConstructor(newConstructor, constructorRequiresReflection, visitorContext);
GeneratorAdapter targetDefinitionGenerator = null;
GeneratorAdapter targetTypeGenerator = null;
if (parentWriter != null) {
proxyBeanDefinitionWriter.visitBeanDefinitionInterface(ProxyBeanDefinition.class);
ClassVisitor pcw = proxyBeanDefinitionWriter.getClassWriter();
targetDefinitionGenerator = new GeneratorAdapter(pcw.visitMethod(ACC_PUBLIC, METHOD_PROXY_TARGET_TYPE.getName(), METHOD_PROXY_TARGET_TYPE.getDescriptor(), null, null), ACC_PUBLIC, METHOD_PROXY_TARGET_TYPE.getName(), METHOD_PROXY_TARGET_TYPE.getDescriptor());
targetDefinitionGenerator.loadThis();
targetDefinitionGenerator.push(getTypeReferenceForName(parentWriter.getBeanDefinitionName()));
targetDefinitionGenerator.returnValue();
targetTypeGenerator = new GeneratorAdapter(pcw.visitMethod(ACC_PUBLIC, METHOD_PROXY_TARGET_CLASS.getName(), METHOD_PROXY_TARGET_CLASS.getDescriptor(), null, null), ACC_PUBLIC, METHOD_PROXY_TARGET_CLASS.getName(), METHOD_PROXY_TARGET_CLASS.getDescriptor());
targetTypeGenerator.loadThis();
targetTypeGenerator.push(getTypeReferenceForName(parentWriter.getBeanTypeName()));
targetTypeGenerator.returnValue();
}
Class<?> interceptedInterface = isIntroduction ? Introduced.class : Intercepted.class;
Type targetType = getTypeReferenceForName(targetClassFullName);
// add the $beanLocator field
if (isProxyTarget) {
proxyClassWriter.visitField(ACC_PRIVATE | ACC_FINAL, FIELD_BEAN_LOCATOR, TYPE_BEAN_LOCATOR.getDescriptor(), null, null);
// add the $beanQualifier field
proxyClassWriter.visitField(ACC_PRIVATE, FIELD_BEAN_QUALIFIER, Type.getType(Qualifier.class).getDescriptor(), null, null);
writeWithQualifierMethod(proxyClassWriter);
if (!lazy || cacheLazyTarget) {
// add the $target field for the target bean
int modifiers = hotswap ? ACC_PRIVATE : ACC_PRIVATE | ACC_FINAL;
proxyClassWriter.visitField(modifiers, FIELD_TARGET, targetType.getDescriptor(), null, null);
}
if (lazy) {
interceptedInterface = InterceptedProxy.class;
proxyClassWriter.visitField(ACC_PRIVATE, FIELD_BEAN_RESOLUTION_CONTEXT, Type.getType(BeanResolutionContext.class).getDescriptor(), null, null);
} else {
interceptedInterface = hotswap ? HotSwappableInterceptedProxy.class : InterceptedProxy.class;
if (hotswap) {
// Add ReadWriteLock field
// private final ReentrantReadWriteLock $target_rwl = new ReentrantReadWriteLock();
proxyClassWriter.visitField(ACC_PRIVATE | ACC_FINAL, FIELD_READ_WRITE_LOCK, TYPE_READ_WRITE_LOCK.getDescriptor(), null, null);
proxyConstructorGenerator.loadThis();
pushNewInstance(proxyConstructorGenerator, TYPE_READ_WRITE_LOCK);
proxyConstructorGenerator.putField(proxyType, FIELD_READ_WRITE_LOCK, TYPE_READ_WRITE_LOCK);
// Add Read Lock field
// private final Lock $target_rl = $target_rwl.readLock();
proxyClassWriter.visitField(ACC_PRIVATE | ACC_FINAL, FIELD_READ_LOCK, TYPE_LOCK.getDescriptor(), null, null);
proxyConstructorGenerator.loadThis();
proxyConstructorGenerator.loadThis();
proxyConstructorGenerator.getField(proxyType, FIELD_READ_WRITE_LOCK, TYPE_READ_WRITE_LOCK);
proxyConstructorGenerator.invokeInterface(Type.getType(ReadWriteLock.class), Method.getMethod(Lock.class.getName() + " readLock()"));
proxyConstructorGenerator.putField(proxyType, FIELD_READ_LOCK, TYPE_LOCK);
// Add Write Lock field
// private final Lock $target_wl = $target_rwl.writeLock();
proxyClassWriter.visitField(ACC_PRIVATE | ACC_FINAL, FIELD_WRITE_LOCK, Type.getDescriptor(Lock.class), null, null);
proxyConstructorGenerator.loadThis();
proxyConstructorGenerator.loadThis();
proxyConstructorGenerator.getField(proxyType, FIELD_READ_WRITE_LOCK, TYPE_READ_WRITE_LOCK);
proxyConstructorGenerator.invokeInterface(Type.getType(ReadWriteLock.class), Method.getMethod(Lock.class.getName() + " writeLock()"));
proxyConstructorGenerator.putField(proxyType, FIELD_WRITE_LOCK, TYPE_LOCK);
}
}
// assign the bean locator
proxyConstructorGenerator.loadThis();
proxyConstructorGenerator.loadArg(beanContextArgumentIndex);
proxyConstructorGenerator.putField(proxyType, FIELD_BEAN_LOCATOR, TYPE_BEAN_LOCATOR);
proxyConstructorGenerator.loadThis();
proxyConstructorGenerator.loadArg(qualifierIndex);
proxyConstructorGenerator.putField(proxyType, FIELD_BEAN_QUALIFIER, Type.getType(Qualifier.class));
if (!lazy) {
proxyConstructorGenerator.loadThis();
pushResolveProxyTargetBean(proxyConstructorGenerator, targetType);
proxyConstructorGenerator.putField(proxyType, FIELD_TARGET, targetType);
} else {
proxyConstructorGenerator.loadThis();
proxyConstructorGenerator.loadArg(beanResolutionContextArgumentIndex);
proxyConstructorGenerator.invokeInterface(Type.getType(BeanResolutionContext.class), Method.getMethod(ReflectionUtils.getRequiredMethod(BeanResolutionContext.class, "copy")));
proxyConstructorGenerator.putField(proxyType, FIELD_BEAN_RESOLUTION_CONTEXT, Type.getType(BeanResolutionContext.class));
}
// Write the Object interceptedTarget() method
writeInterceptedTargetMethod(proxyClassWriter, targetType);
// e. T swap(T newInstance);
if (hotswap && !lazy) {
writeSwapMethod(proxyClassWriter, targetType);
}
}
String[] interfaces = getImplementedInterfaceInternalNames();
if (isInterface && implementInterface) {
String[] adviceInterfaces = { getInternalName(targetClassFullName), Type.getInternalName(interceptedInterface) };
interfaces = ArrayUtils.concat(interfaces, adviceInterfaces);
} else {
String[] adviceInterfaces = { Type.getInternalName(interceptedInterface) };
interfaces = ArrayUtils.concat(interfaces, adviceInterfaces);
}
proxyClassWriter.visit(V1_8, ACC_SYNTHETIC, proxyInternalName, null, isInterface ? TYPE_OBJECT.getInternalName() : getTypeReferenceForName(targetClassFullName).getInternalName(), interfaces);
// set $proxyMethods field
proxyConstructorGenerator.loadThis();
proxyConstructorGenerator.push(proxyMethodCount);
proxyConstructorGenerator.newArray(EXECUTABLE_METHOD_TYPE);
proxyConstructorGenerator.putField(proxyType, FIELD_PROXY_METHODS, FIELD_TYPE_PROXY_METHODS);
// set $interceptors field
proxyConstructorGenerator.loadThis();
proxyConstructorGenerator.push(proxyMethodCount);
proxyConstructorGenerator.newArray(INTERCEPTOR_ARRAY_TYPE);
proxyConstructorGenerator.putField(proxyType, FIELD_INTERCEPTORS, FIELD_TYPE_INTERCEPTORS);
// now initialize the held values
if (isProxyTarget) {
if (proxiedMethods.size() == proxyMethodCount) {
Iterator<MethodRef> iterator = proxyTargetMethods.iterator();
for (int i = 0; i < proxyMethodCount; i++) {
MethodRef methodRef = iterator.next();
// The following will initialize the array of $proxyMethod instances
// Eg. this.$proxyMethods[0] = $PARENT_BEAN.getRequiredMethod("test", new Class[]{String.class});
proxyConstructorGenerator.loadThis();
// Step 1: dereference the array - this.$proxyMethods[0]
proxyConstructorGenerator.getField(proxyType, FIELD_PROXY_METHODS, FIELD_TYPE_PROXY_METHODS);
proxyConstructorGenerator.push(i);
// Step 2: lookup the Method instance from the declaring type
// context.getProxyTargetMethod("test", new Class[]{String.class});
proxyConstructorGenerator.loadArg(beanContextArgumentIndex);
buildProxyLookupArgument(proxyConstructorGenerator, targetType);
proxyConstructorGenerator.loadArg(qualifierIndex);
pushMethodNameAndTypesArguments(proxyConstructorGenerator, methodRef.name, methodRef.argumentTypes);
proxyConstructorGenerator.invokeInterface(Type.getType(ExecutionHandleLocator.class), METHOD_GET_PROXY_TARGET);
// Step 3: store the result in the array
proxyConstructorGenerator.visitInsn(AASTORE);
// Step 4: Resolve the interceptors
// this.$interceptors[0] = InterceptorChain.resolveAroundInterceptors(this.$proxyMethods[0], var2);
pushResolveInterceptorsCall(proxyConstructorGenerator, i, isIntroduction);
}
}
} else if (!proxiedMethods.isEmpty()) {
BeanDefinitionWriter beanDefinitionWriter = parentWriter == null ? proxyBeanDefinitionWriter : parentWriter;
ExecutableMethodsDefinitionWriter executableMethodsDefinitionWriter = beanDefinitionWriter.getExecutableMethodsWriter();
Type executableMethodsDefinitionType = executableMethodsDefinitionWriter.getClassType();
proxyConstructorGenerator.newInstance(executableMethodsDefinitionType);
proxyConstructorGenerator.dup();
if (executableMethodsDefinitionWriter.isSupportsInterceptedProxy()) {
proxyConstructorGenerator.push(true);
proxyConstructorGenerator.invokeConstructor(executableMethodsDefinitionType, new Method(CONSTRUCTOR_NAME, getConstructorDescriptor(boolean.class)));
} else {
proxyConstructorGenerator.invokeConstructor(executableMethodsDefinitionType, new Method(CONSTRUCTOR_NAME, DESCRIPTOR_DEFAULT_CONSTRUCTOR));
}
int executableMethodsDefinitionIndex = proxyConstructorGenerator.newLocal(executableMethodsDefinitionType);
proxyConstructorGenerator.storeLocal(executableMethodsDefinitionIndex, executableMethodsDefinitionType);
for (int i = 0; i < proxyMethodCount; i++) {
MethodRef methodRef = proxiedMethods.get(i);
int methodIndex = methodRef.methodIndex;
boolean introduction = isIntroduction && (executableMethodsDefinitionWriter.isAbstract(methodIndex) || (executableMethodsDefinitionWriter.isInterface(methodIndex) && !executableMethodsDefinitionWriter.isDefault(methodIndex)));
// The following will initialize the array of $proxyMethod instances
// Eg. this.proxyMethods[0] = new $blah0();
proxyConstructorGenerator.loadThis();
proxyConstructorGenerator.getField(proxyType, FIELD_PROXY_METHODS, FIELD_TYPE_PROXY_METHODS);
proxyConstructorGenerator.push(i);
// getExecutableMethodByIndex
proxyConstructorGenerator.loadLocal(executableMethodsDefinitionIndex);
proxyConstructorGenerator.push(methodIndex);
proxyConstructorGenerator.invokeVirtual(executableMethodsDefinitionType, ExecutableMethodsDefinitionWriter.GET_EXECUTABLE_AT_INDEX_METHOD);
proxyConstructorGenerator.visitInsn(AASTORE);
pushResolveInterceptorsCall(proxyConstructorGenerator, i, introduction);
}
}
for (Runnable fieldInjectionPoint : deferredInjectionPoints) {
fieldInjectionPoint.run();
}
constructorWriter.visitInsn(RETURN);
constructorWriter.visitMaxs(DEFAULT_MAX_STACK, 1);
this.constructorWriter.visitEnd();
proxyBeanDefinitionWriter.visitBeanDefinitionEnd();
if (targetDefinitionGenerator != null) {
targetDefinitionGenerator.visitMaxs(1, 1);
targetDefinitionGenerator.visitEnd();
}
if (targetTypeGenerator != null) {
targetTypeGenerator.visitMaxs(1, 1);
targetTypeGenerator.visitEnd();
}
proxyClassWriter.visitEnd();
}
use of io.micronaut.inject.ast.ParameterElement in project micronaut-core by micronaut-projects.
the class BeanDefinitionWriter method createParameterArray.
private int createParameterArray(List<ParameterElement> parameters, GeneratorAdapter buildMethodVisitor) {
final int pLen = parameters.size();
pushNewArray(buildMethodVisitor, Object.class, pLen);
for (int i = 0; i < pLen; i++) {
final ParameterElement parameter = parameters.get(i);
int parameterIndex = i;
pushStoreInArray(buildMethodVisitor, i, pLen, () -> pushConstructorArgument(buildMethodVisitor, parameter.getName(), parameter, parameter.getAnnotationMetadata(), parameterIndex));
}
int local = buildMethodVisitor.newLocal(Type.getType(Object[].class));
buildMethodVisitor.storeLocal(local);
return local;
}
use of io.micronaut.inject.ast.ParameterElement in project micronaut-core by micronaut-projects.
the class DispatchWriter method buildGetTargetMethodByIndex.
/**
* Build get target method by index method if needed.
*
* @param classWriter The classwriter
*/
public void buildGetTargetMethodByIndex(ClassWriter classWriter) {
GeneratorAdapter getTargetMethodByIndex = new GeneratorAdapter(classWriter.visitMethod(Opcodes.ACC_PROTECTED | Opcodes.ACC_FINAL, GET_TARGET_METHOD.getName(), GET_TARGET_METHOD.getDescriptor(), null, null), ACC_PROTECTED | Opcodes.ACC_FINAL, GET_TARGET_METHOD.getName(), GET_TARGET_METHOD.getDescriptor());
getTargetMethodByIndex.loadArg(0);
int[] cases = dispatchTargets.stream().filter(dispatchTarget -> dispatchTarget instanceof MethodDispatchTarget).mapToInt(dispatchTargets::indexOf).toArray();
getTargetMethodByIndex.tableSwitch(cases, new TableSwitchGenerator() {
@Override
public void generateCase(int key, Label end) {
MethodDispatchTarget method = (MethodDispatchTarget) dispatchTargets.get(key);
Type declaringTypeObject = JavaModelUtils.getTypeReference(method.declaringType);
List<ParameterElement> argumentTypes = Arrays.asList(method.methodElement.getSuspendParameters());
getTargetMethodByIndex.push(declaringTypeObject);
getTargetMethodByIndex.push(method.methodElement.getName());
if (!argumentTypes.isEmpty()) {
int len = argumentTypes.size();
Iterator<ParameterElement> iter = argumentTypes.iterator();
pushNewArray(getTargetMethodByIndex, Class.class, len);
for (int i = 0; i < len; i++) {
ParameterElement type = iter.next();
pushStoreInArray(getTargetMethodByIndex, i, len, () -> getTargetMethodByIndex.push(JavaModelUtils.getTypeReference(type)));
}
} else {
getTargetMethodByIndex.getStatic(TYPE_REFLECTION_UTILS, "EMPTY_CLASS_ARRAY", Type.getType(Class[].class));
}
getTargetMethodByIndex.invokeStatic(TYPE_REFLECTION_UTILS, METHOD_GET_REQUIRED_METHOD);
getTargetMethodByIndex.returnValue();
}
@Override
public void generateDefault() {
getTargetMethodByIndex.loadThis();
getTargetMethodByIndex.loadArg(0);
getTargetMethodByIndex.invokeVirtual(thisType, UNKNOWN_DISPATCH_AT_INDEX);
getTargetMethodByIndex.throwException();
}
}, true);
getTargetMethodByIndex.visitMaxs(DEFAULT_MAX_STACK, 1);
getTargetMethodByIndex.visitEnd();
}
use of io.micronaut.inject.ast.ParameterElement in project micronaut-core by micronaut-projects.
the class ExecutableMethodWriter method buildInvokeMethod.
/**
* @param declaringTypeObject The declaring object type
* @param methodName The method name
* @param returnType The return type
* @param argumentTypes The argument types
* @param invokeMethodVisitor The invoke method visitor
*/
protected void buildInvokeMethod(Type declaringTypeObject, String methodName, ClassElement returnType, Collection<ParameterElement> argumentTypes, GeneratorAdapter invokeMethodVisitor) {
Type returnTypeObject = JavaModelUtils.getTypeReference(returnType);
// load this
invokeMethodVisitor.visitVarInsn(ALOAD, 1);
// duplicate target
invokeMethodVisitor.dup();
String methodDescriptor = getMethodDescriptor(returnType, argumentTypes);
if (interceptedProxyClassName != null) {
Label invokeTargetBlock = new Label();
Type interceptedProxyType = getObjectType(interceptedProxyClassName);
// load this.$interceptable field value
invokeMethodVisitor.loadThis();
invokeMethodVisitor.getField(Type.getObjectType(internalName), FIELD_INTERCEPTABLE, Type.getType(boolean.class));
// check if it equals true
invokeMethodVisitor.push(true);
invokeMethodVisitor.ifCmp(Type.BOOLEAN_TYPE, GeneratorAdapter.NE, invokeTargetBlock);
// target instanceOf intercepted proxy
invokeMethodVisitor.loadArg(0);
invokeMethodVisitor.instanceOf(interceptedProxyType);
// check if instanceOf
invokeMethodVisitor.push(true);
invokeMethodVisitor.ifCmp(Type.BOOLEAN_TYPE, GeneratorAdapter.NE, invokeTargetBlock);
pushCastToType(invokeMethodVisitor, interceptedProxyType);
// load arguments
Iterator<ParameterElement> iterator = argumentTypes.iterator();
for (int i = 0; i < argumentTypes.size(); i++) {
invokeMethodVisitor.loadArg(1);
invokeMethodVisitor.push(i);
invokeMethodVisitor.visitInsn(AALOAD);
pushCastToType(invokeMethodVisitor, iterator.next());
}
invokeMethodVisitor.visitMethodInsn(INVOKEVIRTUAL, interceptedProxyType.getInternalName(), interceptedProxyBridgeMethodName, methodDescriptor, false);
if (returnTypeObject.equals(Type.VOID_TYPE)) {
invokeMethodVisitor.visitInsn(ACONST_NULL);
} else {
pushBoxPrimitiveIfNecessary(returnType, invokeMethodVisitor);
}
invokeMethodVisitor.visitInsn(ARETURN);
invokeMethodVisitor.visitLabel(invokeTargetBlock);
// remove parent
invokeMethodVisitor.pop();
}
pushCastToType(invokeMethodVisitor, declaringTypeObject);
boolean hasArgs = !argumentTypes.isEmpty();
if (hasArgs) {
int argCount = argumentTypes.size();
Iterator<ParameterElement> argIterator = argumentTypes.iterator();
for (int i = 0; i < argCount; i++) {
invokeMethodVisitor.visitVarInsn(ALOAD, 2);
invokeMethodVisitor.push(i);
invokeMethodVisitor.visitInsn(AALOAD);
// cast the return value to the correct type
pushCastToType(invokeMethodVisitor, argIterator.next());
}
}
invokeMethodVisitor.visitMethodInsn(isInterface ? INVOKEINTERFACE : INVOKEVIRTUAL, declaringTypeObject.getInternalName(), methodName, methodDescriptor, isInterface);
if (returnTypeObject.equals(Type.VOID_TYPE)) {
invokeMethodVisitor.visitInsn(ACONST_NULL);
} else {
pushBoxPrimitiveIfNecessary(returnType, invokeMethodVisitor);
}
invokeMethodVisitor.visitInsn(ARETURN);
invokeMethodVisitor.visitMaxs(DEFAULT_MAX_STACK, 1);
invokeMethodVisitor.visitEnd();
}
use of io.micronaut.inject.ast.ParameterElement in project micronaut-core by micronaut-projects.
the class ExecutableMethodWriter method visitMethod.
/**
* Write the method.
*
* @param declaringType The declaring type
* @param methodElement The method element
*/
public void visitMethod(TypedElement declaringType, MethodElement methodElement) {
String methodName = methodElement.getName();
List<ParameterElement> argumentTypes = Arrays.asList(methodElement.getSuspendParameters());
Type declaringTypeObject = JavaModelUtils.getTypeReference(declaringType);
boolean hasArgs = !argumentTypes.isEmpty();
classWriter.visit(V1_8, ACC_SYNTHETIC, internalName, null, Type.getInternalName(AbstractExecutableMethod.class), null);
classWriter.visitAnnotation(TYPE_GENERATED.getDescriptor(), false);
// initialize and write the annotation metadata
if (!(annotationMetadata instanceof AnnotationMetadataReference)) {
writeAnnotationMetadataStaticInitializer(classWriter);
}
writeGetAnnotationMetadataMethod(classWriter);
MethodVisitor executorMethodConstructor;
GeneratorAdapter constructorWriter;
if (interceptedProxyBridgeMethodName != null) {
// Create default constructor call other one with 'false'
String descriptor = Type.getDescriptor(boolean.class);
classWriter.visitField(ACC_FINAL | ACC_PRIVATE, FIELD_INTERCEPTABLE, descriptor, null, null);
GeneratorAdapter defaultConstructorWriter = new GeneratorAdapter(startConstructor(classWriter), Opcodes.ACC_PUBLIC, CONSTRUCTOR_NAME, DESCRIPTOR_DEFAULT_CONSTRUCTOR);
String executorMethodConstructorDescriptor = getConstructorDescriptor(boolean.class);
executorMethodConstructor = startConstructor(classWriter, boolean.class);
constructorWriter = new GeneratorAdapter(executorMethodConstructor, Opcodes.ACC_PUBLIC, CONSTRUCTOR_NAME, executorMethodConstructorDescriptor);
defaultConstructorWriter.loadThis();
defaultConstructorWriter.push(false);
defaultConstructorWriter.visitMethodInsn(INVOKESPECIAL, internalName, CONSTRUCTOR_NAME, executorMethodConstructorDescriptor, false);
defaultConstructorWriter.visitInsn(RETURN);
defaultConstructorWriter.visitMaxs(DEFAULT_MAX_STACK, 1);
constructorWriter.loadThis();
constructorWriter.loadArg(0);
constructorWriter.putField(Type.getObjectType(internalName), FIELD_INTERCEPTABLE, Type.getType(boolean.class));
} else {
executorMethodConstructor = startConstructor(classWriter);
constructorWriter = new GeneratorAdapter(executorMethodConstructor, Opcodes.ACC_PUBLIC, CONSTRUCTOR_NAME, DESCRIPTOR_DEFAULT_CONSTRUCTOR);
}
// ALOAD 0
constructorWriter.loadThis();
// load 'this'
constructorWriter.loadThis();
// 1st argument: the declaring class
constructorWriter.push(declaringTypeObject);
// 2nd argument: the method name
constructorWriter.push(methodName);
// 3rd argument the generic return type
ClassElement genericReturnType = methodElement.getGenericReturnType();
if (genericReturnType.isPrimitive() && !genericReturnType.isArray()) {
String constantName = genericReturnType.getName().toUpperCase(Locale.ENGLISH);
// refer to constant for primitives
Type type = Type.getType(Argument.class);
constructorWriter.getStatic(type, constantName, type);
} else {
pushCreateArgument(declaringType.getName(), methodType, classWriter, constructorWriter, genericReturnType.getName(), genericReturnType, genericReturnType.getAnnotationMetadata(), genericReturnType.getTypeArguments(), new HashMap<>(), loadTypeMethods);
}
if (hasArgs) {
// 4th argument: the generic types
pushBuildArgumentsForMethod(methodType.getClassName(), methodType, classWriter, constructorWriter, argumentTypes, new HashMap<>(), loadTypeMethods);
for (ParameterElement pe : argumentTypes) {
DefaultAnnotationMetadata.contributeDefaults(this.annotationMetadata, pe.getAnnotationMetadata());
DefaultAnnotationMetadata.contributeRepeatable(this.annotationMetadata, pe.getGenericType());
}
// now invoke super(..) if no arg constructor
invokeConstructor(executorMethodConstructor, AbstractExecutableMethod.class, Class.class, String.class, Argument.class, Argument[].class);
} else {
invokeConstructor(executorMethodConstructor, AbstractExecutableMethod.class, Class.class, String.class, Argument.class);
}
constructorWriter.visitInsn(RETURN);
constructorWriter.visitMaxs(DEFAULT_MAX_STACK, 1);
// add isAbstract method
GeneratorAdapter isAbstractMethod = new GeneratorAdapter(classWriter.visitMethod(ACC_PUBLIC | ACC_FINAL, METHOD_IS_ABSTRACT.getName(), METHOD_IS_ABSTRACT.getDescriptor(), null, null), ACC_PUBLIC, METHOD_IS_ABSTRACT.getName(), METHOD_IS_ABSTRACT.getDescriptor());
isAbstractMethod.push(isAbstract());
isAbstractMethod.returnValue();
isAbstractMethod.visitMaxs(1, 1);
isAbstractMethod.endMethod();
// add isSuspend method
GeneratorAdapter isSuspendMethod = new GeneratorAdapter(classWriter.visitMethod(ACC_PUBLIC | ACC_FINAL, METHOD_IS_SUSPEND.getName(), METHOD_IS_SUSPEND.getDescriptor(), null, null), ACC_PUBLIC, METHOD_IS_SUSPEND.getName(), METHOD_IS_SUSPEND.getDescriptor());
isSuspendMethod.push(isSuspend());
isSuspendMethod.returnValue();
isSuspendMethod.visitMaxs(1, 1);
isSuspendMethod.endMethod();
// invoke the methods with the passed arguments
String invokeDescriptor = METHOD_INVOKE_INTERNAL.getDescriptor();
String invokeInternalName = METHOD_INVOKE_INTERNAL.getName();
GeneratorAdapter invokeMethod = new GeneratorAdapter(classWriter.visitMethod(Opcodes.ACC_PUBLIC, invokeInternalName, invokeDescriptor, null, null), ACC_PUBLIC, invokeInternalName, invokeDescriptor);
ClassElement returnType = methodElement.isSuspend() ? ClassElement.of(Object.class) : methodElement.getReturnType();
buildInvokeMethod(declaringTypeObject, methodName, returnType, argumentTypes, invokeMethod);
buildResolveTargetMethod(methodName, declaringTypeObject, hasArgs, argumentTypes);
for (GeneratorAdapter method : loadTypeMethods.values()) {
method.visitMaxs(3, 1);
method.visitEnd();
}
}
Aggregations