Skip to content

Commit 5770f69

Browse files
committed
Merge branch '4.8.x' into 4.9.x
2 parents 19d0912 + 051ffdc commit 5770f69

File tree

54 files changed

+1362
-150
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1362
-150
lines changed

Diff for: core-processor/src/main/java/io/micronaut/aop/writer/AopProxyWriter.java

+14-12
Original file line numberDiff line numberDiff line change
@@ -668,24 +668,26 @@ public void visitAroundMethod(TypedElement beanType,
668668

669669
if (!proxiedMethodsRefSet.contains(methodKey)) {
670670

671-
String interceptedProxyClassName = null;
672-
String interceptedProxyBridgeMethodName = null;
671+
ClassTypeDef interceptedProxyDef = null;
672+
MethodDef interceptedProxyBridgeMethod = null;
673673

674674
if (!isProxyTarget) {
675675
// if the target is not being proxied then we need to generate a bridge method and executable method that knows about it
676676

677677
if (!methodElement.isAbstract() || methodElement.isDefault()) {
678-
interceptedProxyClassName = proxyFullName;
679-
interceptedProxyBridgeMethodName = "$$access$$" + methodName;
678+
interceptedProxyDef = ClassTypeDef.of(proxyFullName);
679+
interceptedProxyBridgeMethod = MethodDef.builder("$$access$$" + methodName)
680+
.addModifiers(Modifier.PUBLIC)
681+
.addParameters(argumentTypeList.stream().map(p -> ParameterDef.of(p.getName(), TypeDef.erasure(p.getType()))).toList())
682+
.returns(TypeDef.erasure(returnType))
683+
.build((aThis, methodParameters) -> aThis.superRef((ClassTypeDef) TypeDef.erasure(methodElement.getOwningType()))
684+
.invoke(methodElement, methodParameters)
685+
.returning()
686+
);
680687

681688
// now build a bridge to invoke the original method
682689
proxyBuilder.addMethod(
683-
MethodDef.builder(interceptedProxyBridgeMethodName)
684-
.addModifiers(Modifier.PUBLIC)
685-
.addParameters(argumentTypeList.stream().map(p -> ParameterDef.of(p.getName(), TypeDef.erasure(p.getType()))).toList())
686-
.returns(TypeDef.erasure(returnType))
687-
.build((aThis, methodParameters) -> aThis.superRef((ClassTypeDef) TypeDef.erasure(methodElement.getOwningType()))
688-
.invoke(methodElement, methodParameters).returning())
690+
interceptedProxyBridgeMethod
689691
);
690692
}
691693
}
@@ -694,8 +696,8 @@ public void visitAroundMethod(TypedElement beanType,
694696
int methodIndex = beanDefinitionWriter.visitExecutableMethod(
695697
beanType,
696698
methodElement,
697-
interceptedProxyClassName,
698-
interceptedProxyBridgeMethodName
699+
interceptedProxyDef,
700+
interceptedProxyBridgeMethod
699701
);
700702
int index = proxyMethodCount++;
701703

Diff for: core-processor/src/main/java/io/micronaut/inject/annotation/AbstractAnnotationMetadataBuilder.java

+24-4
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,16 @@ public static void clearMutated() {
15831583
@Internal
15841584
public static void clearMutated(@NonNull Object key) {
15851585
MUTATED_ANNOTATION_METADATA.remove(key);
1586+
Set<Object> keys = new HashSet<>(MUTATED_ANNOTATION_METADATA.keySet());
1587+
for (Object cachedKey : keys) {
1588+
if (cachedKey instanceof Iterable<?> iterable) {
1589+
for (Object object : iterable) {
1590+
if (key.equals(object)) {
1591+
MUTATED_ANNOTATION_METADATA.remove(cachedKey);
1592+
}
1593+
}
1594+
}
1595+
}
15861596
}
15871597

15881598
/**
@@ -1843,24 +1853,34 @@ public interface CachedAnnotationMetadata extends AnnotationMetadataDelegate {
18431853
/**
18441854
* Key used to reference mutated metadata.
18451855
*
1846-
* @param e1 The element 1
1856+
* @param owningType The element 1
18471857
* @param e2 The element 2
18481858
* @param <T> the element type
18491859
*/
18501860
@Internal
1851-
private record Key2<T>(T e1, T e2) {
1861+
private record Key2<T>(T owningType, T e2) implements Iterable<T> {
1862+
@NonNull
1863+
@Override
1864+
public Iterator<T> iterator() {
1865+
return List.of(owningType, e2).iterator();
1866+
}
18521867
}
18531868

18541869
/**
18551870
* Key used to reference mutated metadata.
18561871
*
1857-
* @param e1 The element 1
1872+
* @param owningType The element 1
18581873
* @param e2 The element 2
18591874
* @param e3 The element 3
18601875
* @param <T> the element type
18611876
*/
18621877
@Internal
1863-
private record Key3<T>(T e1, T e2, T e3) {
1878+
private record Key3<T>(T owningType, T e2, T e3) implements Iterable<T> {
1879+
@NonNull
1880+
@Override
1881+
public Iterator<T> iterator() {
1882+
return List.of(owningType, e2, e3).iterator();
1883+
}
18641884
}
18651885

18661886
private static final class DefaultCachedAnnotationMetadata implements CachedAnnotationMetadata {

Diff for: core-processor/src/main/java/io/micronaut/inject/ast/ClassElement.java

+11
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,17 @@ default boolean isTypeVariable() {
101101
return false;
102102
}
103103

104+
/**
105+
*
106+
* @param kind The kind of error
107+
* @return Whether errors are present in the type element.
108+
* @since 4.7.18
109+
*/
110+
@Experimental
111+
default boolean hasUnresolvedTypes(UnresolvedTypeKind... kind) {
112+
return false;
113+
}
114+
104115
/**
105116
* @return Whether this is a generic placeholder.
106117
* @see GenericPlaceholderElement

Diff for: core-processor/src/main/java/io/micronaut/inject/ast/MemberElement.java

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package io.micronaut.inject.ast;
1717

1818
import io.micronaut.core.annotation.AnnotationMetadata;
19+
import io.micronaut.core.annotation.NextMajorVersion;
1920
import io.micronaut.core.annotation.NonNull;
2021
import io.micronaut.core.annotation.ReflectiveAccess;
2122

@@ -107,6 +108,7 @@ default boolean isAccessible() {
107108
* @return Will return {@code true} if is accessible.
108109
* @since 4.3.0
109110
*/
111+
@NextMajorVersion("The ReflectiveAccess should not be checked here and accessibility should fail if ReflectiveAccess is not present")
110112
default boolean isAccessible(@NonNull ClassElement callingType, boolean allowReflection) {
111113
if (isPublic()) {
112114
return true;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2017-2025 original authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.micronaut.inject.ast;
17+
18+
import io.micronaut.core.annotation.Experimental;
19+
20+
/**
21+
* Used in conjunction with {@link ClassElement#hasUnresolvedTypes(UnresolvedTypeKind...)} to support
22+
* checking whether a type has unresolved type references.
23+
*
24+
* <p>Currently only checking the interface and class hierarchy is supported but this enum could be extended further
25+
* in the future to support other cases.
26+
* </p>
27+
*
28+
* @since 4.7.18
29+
* @see ClassElement#hasUnresolvedTypes(UnresolvedTypeKind...)
30+
*/
31+
@Experimental
32+
public enum UnresolvedTypeKind {
33+
/**
34+
* An interface type reference.
35+
*/
36+
INTERFACE,
37+
/**
38+
* A super class type reference.
39+
*/
40+
SUPERCLASS
41+
}

Diff for: core-processor/src/main/java/io/micronaut/inject/ast/utils/EnclosedElementsQuery.java

+12-3
Original file line numberDiff line numberDiff line change
@@ -314,17 +314,26 @@ private <T extends Element> void reduce(Collection<T> collectedElements,
314314
continue;
315315
}
316316
T newElement = convertElement(result, element);
317-
317+
String newElementName = newElement.getName();
318318
for (Iterator<T> iterator = collectedElements.iterator(); iterator.hasNext(); ) {
319319
T existingElement = iterator.next();
320-
if (!existingElement.getName().equals(newElement.getName())) {
320+
if (!existingElement.getName().equals(newElementName)) {
321321
continue;
322322
}
323323
if (isInterface) {
324324
if (existingElement == newElement) {
325325
continue classElements;
326326
}
327-
if (reduce.test(existingElement, newElement)) {
327+
if (!newElement.isAbstract()) {
328+
if (reduce.test(newElement, existingElement)) {
329+
iterator.remove();
330+
addedFromClassElements.add(newElement);
331+
continue classElements;
332+
}
333+
if (!existingElement.isAbstract() && reduce.test(existingElement, newElement)) {
334+
continue classElements;
335+
}
336+
} else if (reduce.test(existingElement, newElement)) {
328337
continue classElements;
329338
} else if (includesAbstract && reduce.test(newElement, existingElement)) {
330339
iterator.remove();

Diff for: core-processor/src/main/java/io/micronaut/inject/beans/visitor/BeanIntrospectionWriter.java

+18-6
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ final class BeanIntrospectionWriter implements OriginatingElements, ClassOutputW
222222
this.beanType = ClassTypeDef.of(beanClassElement);
223223
this.introspectionName = computeShortIntrospectionName(targetPackage, name);
224224
this.introspectionTypeDef = ClassTypeDef.of(introspectionName);
225-
this.dispatchWriter = new DispatchWriter();
225+
this.dispatchWriter = new DispatchWriter(introspectionName);
226226
this.annotationMetadata = annotationMetadata.getTargetAnnotationMetadata();
227227
this.originatingElements = OriginatingElements.of(beanClassElement);
228228
evaluatedExpressionProcessor = new EvaluatedExpressionProcessor(visitorContext, beanClassElement);
@@ -253,7 +253,7 @@ final class BeanIntrospectionWriter implements OriginatingElements, ClassOutputW
253253
this.beanType = ClassTypeDef.of(beanClassElement);
254254
this.introspectionName = computeIntrospectionName(targetPackage, className);
255255
this.introspectionTypeDef = ClassTypeDef.of(introspectionName);
256-
this.dispatchWriter = new DispatchWriter();
256+
this.dispatchWriter = new DispatchWriter(introspectionName);
257257
this.annotationMetadata = annotationMetadata.getTargetAnnotationMetadata();
258258
this.originatingElements = OriginatingElements.of(originatingElement);
259259
evaluatedExpressionProcessor = new EvaluatedExpressionProcessor(visitorContext, beanClassElement);
@@ -936,12 +936,12 @@ private MethodDef getInstantiateMethod(MethodElement constructor, Method method)
936936
return MethodDef.override(method)
937937
.build((aThis, methodParameters) -> {
938938
if (method.getParameters().length == 0) {
939-
return MethodGenUtils.invokeBeanConstructor(constructor, true, null).returning();
939+
return MethodGenUtils.invokeBeanConstructor(ClassElement.of(introspectionName), constructor, true, null).returning();
940940
} else {
941941
List<ExpressionDef> values = IntStream.range(0, constructor.getSuspendParameters().length)
942942
.<ExpressionDef>mapToObj(index -> methodParameters.get(0).arrayElement(index))
943943
.toList();
944-
return MethodGenUtils.invokeBeanConstructor(constructor, true, values).returning();
944+
return MethodGenUtils.invokeBeanConstructor(ClassElement.of(introspectionName), constructor, true, values).returning();
945945
}
946946
});
947947
}
@@ -1052,7 +1052,7 @@ public TypedElement getDeclaringType() {
10521052
/**
10531053
* Copy constructor "with" method writer.
10541054
*/
1055-
private static final class CopyConstructorDispatchTarget implements DispatchWriter.DispatchTarget {
1055+
private final class CopyConstructorDispatchTarget implements DispatchWriter.DispatchTarget {
10561056

10571057
private final ClassTypeDef beanType;
10581058
private final List<BeanPropertyData> beanProperties;
@@ -1120,6 +1120,10 @@ private StatementDef createStatement(ExpressionDef caseExpression, ExpressionDef
11201120
FieldElement field = fieldGetDispatchTarget.getField();
11211121
propertyType = field.getGenericType();
11221122
member = field;
1123+
} else if (dispatchTarget instanceof DispatchWriter.FieldGetReflectionDispatchTarget fieldGetDispatchTarget) {
1124+
FieldElement field = fieldGetDispatchTarget.getField();
1125+
propertyType = field.getGenericType();
1126+
member = field;
11231127
} else {
11241128
throw new IllegalStateException();
11251129
}
@@ -1170,7 +1174,7 @@ private StatementDef createStatement(ExpressionDef caseExpression, ExpressionDef
11701174
}
11711175

11721176
// NOTE: It doesn't make sense to check defaults for the copy constructor
1173-
ExpressionDef newInstance = MethodGenUtils.invokeBeanConstructor(constructor, false, values);
1177+
ExpressionDef newInstance = MethodGenUtils.invokeBeanConstructor(ClassElement.of(introspectionName), constructor, false, values);
11741178
return withSetSettersAndFields(newInstance, prevBeanVar, constructorProps);
11751179
});
11761180
} else {
@@ -1205,6 +1209,9 @@ private StatementDef withSetSettersAndFields(ExpressionDef newInstance,
12051209
} else if (readDispatch instanceof DispatchWriter.FieldGetDispatchTarget fieldGetDispatchTarget) {
12061210
FieldElement fieldElement = fieldGetDispatchTarget.getField();
12071211
oldValueExp = prevBeanVar.field(fieldElement);
1212+
} else if (readDispatch instanceof DispatchWriter.FieldGetReflectionDispatchTarget fieldGetDispatchTarget) {
1213+
FieldElement fieldElement = fieldGetDispatchTarget.getField();
1214+
oldValueExp = prevBeanVar.field(fieldElement);
12081215
} else {
12091216
throw new IllegalStateException();
12101217
}
@@ -1223,6 +1230,11 @@ private StatementDef withSetSettersAndFields(ExpressionDef newInstance,
12231230
statements.add(
12241231
newBeanVar.field(fieldElement).assign(oldValueExp)
12251232
);
1233+
} else if (writeDispatch instanceof DispatchWriter.FieldSetReflectionDispatchTarget fieldSetDispatchTarget) {
1234+
FieldElement fieldElement = fieldSetDispatchTarget.getField();
1235+
statements.add(
1236+
newBeanVar.field(fieldElement).assign(oldValueExp)
1237+
);
12261238
} else {
12271239
throw new IllegalStateException();
12281240
}

Diff for: core-processor/src/main/java/io/micronaut/inject/beans/visitor/IntrospectedTypeElementVisitor.java

+9-4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import io.micronaut.inject.ast.MethodElement;
3434
import io.micronaut.inject.ast.PropertyElement;
3535
import io.micronaut.inject.ast.PropertyElementQuery;
36+
import io.micronaut.inject.processing.ProcessingException;
3637
import io.micronaut.inject.visitor.ElementPostponedToNextRoundException;
3738
import io.micronaut.inject.visitor.TypeElementVisitor;
3839
import io.micronaut.inject.visitor.VisitorContext;
@@ -194,6 +195,10 @@ private void processBuilderDefinition(ClassElement element, VisitorContext conte
194195
);
195196
} else if (element.hasDeclaredAnnotation(ANN_LOMBOK_BUILDER)) {
196197
AnnotationValue<Annotation> lombokBuilder = element.getAnnotation(ANN_LOMBOK_BUILDER);
198+
String lombokBuilderAccessType = lombokBuilder.stringValue("access").orElse("");
199+
if ("PRIVATE".equals(lombokBuilderAccessType)) {
200+
return;
201+
}
197202
String builderMethod = lombokBuilder.stringValue("builderMethodName").orElse("builder");
198203
MethodElement methodElement = element
199204
.getEnclosedElement(ElementQuery.ALL_METHODS.onlyStatic()
@@ -248,10 +253,10 @@ private void processBuilderDefinition(ClassElement element, VisitorContext conte
248253
targetPackage
249254
);
250255
} else {
251-
context.fail("Builder return type is not public. The method must be static and accessible.", methodElement);
256+
throw new ProcessingException(methodElement, "Builder return type is not public. The method must be static and accessible.");
252257
}
253258
} else {
254-
context.fail("Method " + builderMethod + "() specified by builderMethod not found. The method must be static and accessible.", element);
259+
throw new ProcessingException(element, "Method " + builderMethod + "() specified by builderMethod not found. The method must be static and accessible.");
255260
}
256261
} else if (builderClass != null) {
257262
ClassElement builderClassElement = context.getClassElement(builderClass.getName()).orElse(null);
@@ -272,10 +277,10 @@ private void processBuilderDefinition(ClassElement element, VisitorContext conte
272277
index,
273278
targetPackage);
274279
} else {
275-
context.fail("Builder class not found on compilation classpath: " + builderClass.getName(), element);
280+
throw new ProcessingException(element, "Builder class not found on compilation classpath: " + builderClass.getName());
276281
}
277282
} else {
278-
context.fail("When specifying the 'builder' member of @Introspected you must supply either a builderClass or builderMethod", element);
283+
throw new ProcessingException(element, "When specifying the 'builder' member of @Introspected you must supply either a builderClass or builderMethod");
279284
}
280285
}
281286

Diff for: core-processor/src/main/java/io/micronaut/inject/writer/BeanDefinitionWriter.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -1831,7 +1831,7 @@ private ClassTypeDef createConstructorInterceptor(ConstructorBuildMethodDefiniti
18311831
List<ExpressionDef> values = IntStream.range(0, parameters.length)
18321832
.<ExpressionDef>mapToObj(index -> methodParameters.get(0).arrayElement(index).cast(TypeDef.erasure(parameters[index].getType())))
18331833
.toList();
1834-
return MethodGenUtils.invokeBeanConstructor(constructorBuildMethodDefinition.constructor, true, values)
1834+
return MethodGenUtils.invokeBeanConstructor(ClassElement.of(beanDefinitionName), constructorBuildMethodDefinition.constructor, true, values)
18351835
.returning();
18361836
})
18371837
);
@@ -2620,14 +2620,14 @@ public int visitExecutableMethod(TypedElement declaringBean,
26202620
* @param declaringType The declaring type of the method. Either a Class or a string representing the
26212621
* name of the type
26222622
* @param methodElement The method element
2623-
* @param interceptedProxyClassName The intercepted proxy class name
2624-
* @param interceptedProxyBridgeMethodName The intercepted proxy bridge method name
2623+
* @param interceptedProxyType The intercepted proxy type
2624+
* @param interceptedProxyBridgeMethod The intercepted proxy bridge method name
26252625
* @return The index of a new method.
26262626
*/
26272627
public int visitExecutableMethod(TypedElement declaringType,
26282628
MethodElement methodElement,
2629-
String interceptedProxyClassName,
2630-
String interceptedProxyBridgeMethodName) {
2629+
ClassTypeDef interceptedProxyType,
2630+
MethodDef interceptedProxyBridgeMethod) {
26312631

26322632
if (executableMethodsDefinitionWriter == null) {
26332633
executableMethodsDefinitionWriter = new ExecutableMethodsDefinitionWriter(
@@ -2639,7 +2639,7 @@ public int visitExecutableMethod(TypedElement declaringType,
26392639
visitorContext
26402640
);
26412641
}
2642-
return executableMethodsDefinitionWriter.visitExecutableMethod(declaringType, methodElement, interceptedProxyClassName, interceptedProxyBridgeMethodName);
2642+
return executableMethodsDefinitionWriter.visitExecutableMethod(declaringType, methodElement, interceptedProxyType, interceptedProxyBridgeMethod);
26432643
}
26442644

26452645
@Override

0 commit comments

Comments
 (0)