use of io.micronaut.inject.writer.ExecutableMethodsDefinitionWriter 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();
}
Aggregations