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);
}
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);
}
}
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));
}
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();
}
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();
}
Aggregations