use of io.micronaut.inject.writer.BeanDefinitionWriter in project micronaut-core by micronaut-projects.
the class JavaBeanDefinitionBuilder method createChildBean.
@Override
protected AbstractBeanDefinitionBuilder createChildBean(FieldElement producerField) {
final ClassElement parentType = getBeanType();
return new JavaBeanDefinitionBuilder(JavaBeanDefinitionBuilder.this.getOriginatingElement(), producerField.getGenericField().getType(), JavaBeanDefinitionBuilder.this.metadataBuilder, (JavaVisitorContext) JavaBeanDefinitionBuilder.this.visitorContext) {
@Override
public Element getProducingElement() {
return producerField;
}
@Override
public ClassElement getDeclaringElement() {
return producerField.getDeclaringType();
}
@Override
protected BeanDefinitionWriter createBeanDefinitionWriter() {
final BeanDefinitionWriter writer = super.createBeanDefinitionWriter();
final JavaElementFactory elementFactory = ((JavaVisitorContext) visitorContext).getElementFactory();
final VariableElement variableElement = (VariableElement) producerField.getNativeType();
writer.visitBeanFactoryField(parentType, elementFactory.newFieldElement(parentType, variableElement, new AnnotationMetadataHierarchy(parentType.getDeclaredMetadata(), producerField.getDeclaredMetadata())));
return writer;
}
};
}
use of io.micronaut.inject.writer.BeanDefinitionWriter 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.writer.BeanDefinitionWriter 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);
}
}
use of io.micronaut.inject.writer.BeanDefinitionWriter in project micronaut-core by micronaut-projects.
the class JavaBeanDefinitionBuilder method createChildBean.
@Override
protected AbstractBeanDefinitionBuilder createChildBean(MethodElement producerMethod) {
final ClassElement parentType = getBeanType();
return new JavaBeanDefinitionBuilder(JavaBeanDefinitionBuilder.this.getOriginatingElement(), producerMethod.getGenericReturnType(), JavaBeanDefinitionBuilder.this.metadataBuilder, (JavaVisitorContext) JavaBeanDefinitionBuilder.this.visitorContext) {
@Override
public Element getProducingElement() {
return producerMethod;
}
@Override
public ClassElement getDeclaringElement() {
return producerMethod.getDeclaringType();
}
@Override
protected BeanDefinitionWriter createBeanDefinitionWriter() {
final BeanDefinitionWriter writer = super.createBeanDefinitionWriter();
final JavaElementFactory elementFactory = ((JavaVisitorContext) visitorContext).getElementFactory();
final ExecutableElement variableElement = (ExecutableElement) producerMethod.getNativeType();
writer.visitBeanFactoryMethod(parentType, elementFactory.newMethodElement(parentType, variableElement, new AnnotationMetadataHierarchy(parentType.getDeclaredMetadata(), producerMethod.getDeclaredMetadata())));
return writer;
}
};
}
use of io.micronaut.inject.writer.BeanDefinitionWriter in project micronaut-core by micronaut-projects.
the class GroovyBeanDefinitionBuilder method createChildBean.
@Override
protected AbstractBeanDefinitionBuilder createChildBean(FieldElement producerField) {
final ClassElement parentType = getBeanType();
return new GroovyBeanDefinitionBuilder(GroovyBeanDefinitionBuilder.this.getOriginatingElement(), producerField.getGenericField().getType(), GroovyBeanDefinitionBuilder.this.metadataBuilder, GroovyBeanDefinitionBuilder.this.visitorContext) {
@Override
public Element getProducingElement() {
return producerField;
}
@Override
public ClassElement getDeclaringElement() {
return producerField.getDeclaringType();
}
@Override
protected BeanDefinitionWriter createBeanDefinitionWriter() {
final BeanDefinitionWriter writer = super.createBeanDefinitionWriter();
final GroovyElementFactory elementFactory = ((GroovyVisitorContext) visitorContext).getElementFactory();
final FieldNode fieldNode = (FieldNode) producerField.getNativeType();
writer.visitBeanFactoryField(parentType, elementFactory.newFieldElement(parentType, fieldNode, new AnnotationMetadataHierarchy(parentType.getDeclaredMetadata(), producerField.getDeclaredMetadata())));
return writer;
}
};
}
Aggregations