Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ArC - support multiple interceptor methods in a class hierarchy and around invoke method declared on target class #32730

Merged
merged 5 commits into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ public class BeanInfo implements InjectionTargetInfo {

private final String targetPackageName;

private final List<MethodInfo> aroundInvokes;

BeanInfo(AnnotationTarget target, BeanDeployment beanDeployment, ScopeInfo scope, Set<Type> types,
Set<AnnotationInstance> qualifiers, List<Injection> injections, BeanInfo declaringBean, DisposerInfo disposer,
boolean alternative, List<StereotypeInfo> stereotypes, String name, boolean isDefaultBean, String targetPackageName,
Expand Down Expand Up @@ -143,6 +145,7 @@ public class BeanInfo implements InjectionTargetInfo {
this.lifecycleInterceptors = Collections.emptyMap();
this.forceApplicationClass = forceApplicationClass;
this.targetPackageName = targetPackageName;
this.aroundInvokes = isInterceptor() || isDecorator() ? List.of() : Beans.getAroundInvokes(implClazz, beanDeployment);
}

@Override
Expand Down Expand Up @@ -360,8 +363,10 @@ public boolean hasAroundInvokeInterceptors() {
}

boolean isSubclassRequired() {
return !interceptedMethods.isEmpty() || !decoratedMethods.isEmpty()
|| lifecycleInterceptors.containsKey(InterceptionType.PRE_DESTROY);
return !interceptedMethods.isEmpty()
|| !decoratedMethods.isEmpty()
|| lifecycleInterceptors.containsKey(InterceptionType.PRE_DESTROY)
|| !aroundInvokes.isEmpty();
}

/**
Expand Down Expand Up @@ -445,6 +450,18 @@ public List<DecoratorInfo> getBoundDecorators() {
return bound;
}

/**
*
* @return the list of around invoke interceptor methods declared in the hierarchy of a bean class
*/
List<MethodInfo> getAroundInvokes() {
return aroundInvokes;
}

boolean hasAroundInvokes() {
return !aroundInvokes.isEmpty();
}

public DisposerInfo getDisposer() {
return disposer;
}
Expand Down Expand Up @@ -602,8 +619,8 @@ private Map<MethodInfo, InterceptionInfo> initInterceptedMethods(List<Throwable>
}
}

Set<MethodInfo> finalMethods = Methods.addInterceptedMethodCandidates(beanDeployment, target.get().asClass(),
candidates, classLevelBindings, bytecodeTransformerConsumer, transformUnproxyableClasses);
Set<MethodInfo> finalMethods = Methods.addInterceptedMethodCandidates(this, candidates, classLevelBindings,
bytecodeTransformerConsumer, transformUnproxyableClasses);
if (!finalMethods.isEmpty()) {
String additionalError = "";
if (finalMethods.stream().anyMatch(KotlinUtils::isNoninterceptableKotlinMethod)) {
Expand All @@ -620,7 +637,7 @@ private Map<MethodInfo, InterceptionInfo> initInterceptedMethods(List<Throwable>
for (Entry<MethodKey, Set<AnnotationInstance>> entry : candidates.entrySet()) {
List<InterceptorInfo> interceptors = beanDeployment.getInterceptorResolver()
.resolve(InterceptionType.AROUND_INVOKE, entry.getValue());
if (!interceptors.isEmpty()) {
if (!interceptors.isEmpty() || !aroundInvokes.isEmpty()) {
interceptedMethods.put(entry.getKey().method, new InterceptionInfo(interceptors, entry.getValue()));
}
}
Expand Down Expand Up @@ -651,7 +668,8 @@ private Map<MethodInfo, DecorationInfo> initDecoratedMethods() {
ClassInfo classInfo = target.get().asClass();
addDecoratedMethods(candidates, classInfo, classInfo, bound,
new SubclassSkipPredicate(beanDeployment.getAssignabilityCheck()::isAssignableFrom,
beanDeployment.getBeanArchiveIndex(), beanDeployment.getObserverAndProducerMethods()));
beanDeployment.getBeanArchiveIndex(), beanDeployment.getObserverAndProducerMethods(),
beanDeployment.getAnnotationStore()));

Map<MethodInfo, DecorationInfo> decoratedMethods = new HashMap<>(candidates.size());
for (Entry<MethodKey, DecorationInfo> entry : candidates.entrySet()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ public List<Resource> generateResources(ReflectionRegistration reflectionRegistr
}

SubclassGenerator subclassGenerator = new SubclassGenerator(annotationLiterals, applicationClassPredicate,
generateSources, refReg, existingClasses);
generateSources, refReg, existingClasses, privateMembers);

ObserverGenerator observerGenerator = new ObserverGenerator(annotationLiterals, applicationClassPredicate,
privateMembers, generateSources, refReg, existingClasses, observerToGeneratedName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,35 @@ static List<MethodInfo> getCallbacks(ClassInfo beanClass, DotName annotation, In
return callbacks;
}

static List<MethodInfo> getAroundInvokes(ClassInfo beanClass, BeanDeployment deployment) {
AnnotationStore store = deployment.getAnnotationStore();
List<MethodInfo> methods = new ArrayList<>();

List<MethodInfo> allMethods = new ArrayList<>();
ClassInfo aClass = beanClass;
while (aClass != null) {
int aroundInvokesFound = 0;
for (MethodInfo method : aClass.methods()) {
if (Modifier.isStatic(method.flags())) {
continue;
}
if (store.hasAnnotation(method, DotNames.AROUND_INVOKE)) {
InterceptorInfo.addInterceptorMethod(allMethods, methods, method);
if (++aroundInvokesFound > 1) {
throw new DefinitionException(
"Multiple @AroundInvoke interceptor methods declared on class: " + aClass);
}
}
allMethods.add(method);
}
DotName superTypeName = aClass.superName();
aClass = superTypeName == null || DotNames.OBJECT.equals(superTypeName) ? null
: getClassByName(deployment.getBeanArchiveIndex(), superTypeName);
}
Collections.reverse(methods);
return methods.isEmpty() ? List.of() : List.copyOf(methods);
}

static void analyzeType(Type type, BeanDeployment beanDeployment) {
if (type.kind() == Type.Kind.PARAMETERIZED_TYPE) {
for (Type argument : type.asParameterizedType().arguments()) {
Expand Down
Loading