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: fix some scenarios with generic decorators #33841

Merged
merged 1 commit into from
Jun 7, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
Expand Down Expand Up @@ -350,23 +351,41 @@ List<MethodInfo> getInterceptedOrDecoratedMethods() {
Set<MethodInfo> getDecoratedMethods(DecoratorInfo decorator) {
Set<MethodInfo> decorated = new HashSet<>();
for (Entry<MethodInfo, DecorationInfo> entry : decoratedMethods.entrySet()) {
if (entry.getValue().decorators.contains(decorator)) {
if (entry.getValue().contains(decorator)) {
decorated.add(entry.getKey());
}
}
return decorated;
}

MethodInfo getDecoratedMethod(MethodInfo decoratorMethod, DecoratorInfo decorator) {
for (Entry<MethodInfo, DecorationInfo> e : decoratedMethods.entrySet()) {
for (DecoratorMethod dm : e.getValue().decoratorMethods) {
if (dm.decorator.equals(decorator) && dm.method.equals(decoratorMethod)) {
return e.getKey();
}
}
}
return null;
}

// Returns a map of method descriptor -> next decorator in the chain
// e.g. foo() -> BravoDecorator
Map<MethodDescriptor, DecoratorInfo> getNextDecorators(DecoratorInfo decorator) {
Map<MethodDescriptor, DecoratorInfo> next = new HashMap<>();
Map<MethodDescriptor, DecoratorMethod> getNextDecorators(DecoratorInfo decorator) {
Map<MethodDescriptor, DecoratorMethod> next = new HashMap<>();
for (Entry<MethodInfo, DecorationInfo> entry : decoratedMethods.entrySet()) {
List<DecoratorInfo> decorators = entry.getValue().decorators;
int index = decorators.indexOf(decorator);
List<DecoratorMethod> decoratorMethods = entry.getValue().decoratorMethods;
int index = -1;
for (ListIterator<DecoratorMethod> it = decoratorMethods.listIterator(); it.hasNext();) {
DecoratorMethod dm = it.next();
if (dm.decorator.equals(decorator)) {
index = it.previousIndex();
break;
}
}
if (index != -1) {
if (index != (decorators.size() - 1)) {
next.put(MethodDescriptor.of(entry.getKey()), decorators.get(index + 1));
if (index != (decoratorMethods.size() - 1)) {
next.put(MethodDescriptor.of(entry.getKey()), decoratorMethods.get(index + 1));
}
}
}
Expand Down Expand Up @@ -456,9 +475,9 @@ public List<DecoratorInfo> getBoundDecorators() {
}
List<DecoratorInfo> bound = new ArrayList<>();
for (DecorationInfo decoration : decoratedMethods.values()) {
for (DecoratorInfo decorator : decoration.decorators) {
if (!bound.contains(decorator)) {
bound.add(decorator);
for (DecoratorMethod dm : decoration.decoratorMethods) {
if (!bound.contains(dm.decorator)) {
bound.add(dm.decorator);
}
}
}
Expand Down Expand Up @@ -692,7 +711,7 @@ private Map<MethodInfo, DecorationInfo> initDecoratedMethods() {
beanDeployment.getBeanArchiveIndex(), beanDeployment.getObserverAndProducerMethods(),
beanDeployment.getAnnotationStore()));

Map<MethodInfo, DecorationInfo> decoratedMethods = new HashMap<>(candidates.size());
Map<MethodInfo, DecorationInfo> decoratedMethods = new HashMap<>();
for (Entry<MethodKey, DecorationInfo> entry : candidates.entrySet()) {
decoratedMethods.put(entry.getKey().method, entry.getValue());
}
Expand All @@ -706,9 +725,10 @@ private void addDecoratedMethods(Map<MethodKey, DecorationInfo> decoratedMethods
if (skipPredicate.test(method)) {
continue;
}
List<DecoratorInfo> matching = findMatchingDecorators(method, boundDecorators);
if (!matching.isEmpty()) {
decoratedMethods.computeIfAbsent(new MethodKey(method), key -> new DecorationInfo(matching));
List<DecoratorMethod> matching = findMatchingDecorators(method, boundDecorators);
MethodKey key = new MethodKey(method);
if (!matching.isEmpty() && !decoratedMethods.containsKey(key)) {
decoratedMethods.put(key, new DecorationInfo(matching));
}
}
skipPredicate.methodsProcessed();
Expand All @@ -720,12 +740,11 @@ private void addDecoratedMethods(Map<MethodKey, DecorationInfo> decoratedMethods
}
}

private List<DecoratorInfo> findMatchingDecorators(MethodInfo method, List<DecoratorInfo> decorators) {
private List<DecoratorMethod> findMatchingDecorators(MethodInfo method, List<DecoratorInfo> decorators) {
List<Type> methodParams = method.parameterTypes();
List<DecoratorInfo> matching = new ArrayList<>(decorators.size());
List<DecoratorMethod> matching = new ArrayList<>(decorators.size());
for (DecoratorInfo decorator : decorators) {
for (Type decoratedType : decorator.getDecoratedTypes()) {
// Converter<String>
ClassInfo decoratedTypeClass = decorator.getDeployment().getBeanArchiveIndex()
.getClassByName(decoratedType.name());
if (decoratedTypeClass == null) {
Expand All @@ -750,13 +769,20 @@ private List<DecoratorInfo> findMatchingDecorators(MethodInfo method, List<Decor
decoratedMethod,
beanDeployment.getBeanArchiveIndex());
for (int i = 0; i < methodParams.size(); i++) {
if (!beanDeployment.getDelegateInjectionPointResolver().matches(decoratedMethodParams.get(i),
methodParams.get(i))) {
matches = false;
BeanResolver resolver = beanDeployment.getDelegateInjectionPointResolver();
Type decoratedParam = decoratedMethodParams.get(i);
if (decoratedParam.kind() == org.jboss.jandex.Type.Kind.TYPE_VARIABLE) {
if (!resolver.matchTypeArguments(decoratedParam, methodParams.get(i))) {
matches = false;
}
} else {
if (!resolver.matches(decoratedParam, methodParams.get(i))) {
matches = false;
}
}
}
if (matches) {
matching.add(decorator);
matching.add(new DecoratorMethod(decorator, decoratedMethod));
}
}
}
Expand Down Expand Up @@ -942,14 +968,39 @@ boolean isEmpty() {

static class DecorationInfo {

final List<DecoratorInfo> decorators;
final List<DecoratorMethod> decoratorMethods;

public DecorationInfo(List<DecoratorInfo> decorators) {
this.decorators = decorators;
public DecorationInfo(List<DecoratorMethod> decoratorMethods) {
this.decoratorMethods = decoratorMethods;
}

boolean isEmpty() {
return decorators.isEmpty();
return decoratorMethods.isEmpty();
}

boolean contains(DecoratorInfo decorator) {
for (DecoratorMethod dm : decoratorMethods) {
if (dm.decorator.equals(decorator)) {
return true;
}
}
return false;
}

DecoratorMethod firstDecoratorMethod() {
return decoratorMethods.get(0);
}

}

static class DecoratorMethod {

final DecoratorInfo decorator;
final MethodInfo method;

public DecoratorMethod(DecoratorInfo decorator, MethodInfo method) {
this.decorator = Objects.requireNonNull(decorator);
this.method = Objects.requireNonNull(method);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,11 @@ default Set<BeanInfo> resolveBeans(Type requiredType, AnnotationInstance... requ
*/
boolean hasQualifier(Collection<AnnotationInstance> qualifiers, AnnotationInstance requiredQualifier);

/**
* @param requiredTypeArgument
* @param typeArgument
* @return {@code true} if the required type argument matches the given type argument, {@code false} otherwise
*/
boolean matchTypeArguments(Type requiredTypeArgument, Type typeArgument);

}
Original file line number Diff line number Diff line change
Expand Up @@ -185,19 +185,19 @@ boolean matchesNoBoxing(Type requiredType, Type beanType) {
throw new IllegalArgumentException("Invalid argument combination " + requiredType + "; " + beanType);
}
for (int i = 0; i < requiredTypeArguments.size(); i++) {
if (!parametersMatch(requiredTypeArguments.get(i), beanTypeArguments.get(i))) {
if (!matchTypeArguments(requiredTypeArguments.get(i), beanTypeArguments.get(i))) {
return false;
}
}
return true;
}
} else if (WILDCARD_TYPE.equals(requiredType.kind())) {
return parametersMatch(requiredType, beanType);
return matchTypeArguments(requiredType, beanType);
}
return false;
}

boolean parametersMatch(Type requiredParameter, Type beanParameter) {
public boolean matchTypeArguments(Type requiredParameter, Type beanParameter) {
if (isActualType(requiredParameter) && isActualType(beanParameter)) {
/*
* the required type parameter and the bean type parameter are actual types with identical raw type, and, if the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class DelegateInjectionPointResolverImpl extends BeanResolverImpl {
}

@Override
boolean parametersMatch(Type delegateType, Type beanParameter) {
public boolean matchTypeArguments(Type delegateType, Type beanParameter) {
// this is the same as for bean types
if (isActualType(delegateType) && isActualType(beanParameter)) {
/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ private static boolean skipForClientProxy(MethodInfo method, boolean transformUn
}

static boolean skipForDelegateSubclass(MethodInfo method) {
if (Modifier.isStatic(method.flags())) {
if (Modifier.isStatic(method.flags()) || method.isSynthetic() || isDefault(method)) {
return true;
}
if (IGNORED_METHODS.contains(method.name())) {
Expand All @@ -153,6 +153,12 @@ static boolean skipForDelegateSubclass(MethodInfo method) {
return false;
}

static boolean isDefault(MethodInfo method) {
// Default methods are public non-abstract instance methods declared in an interface
return ((method.flags() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC)
&& method.declaringClass().isInterface();
}

static boolean isObjectToString(MethodInfo method) {
return method.declaringClass().name().equals(DotNames.OBJECT) && method.name().equals(TO_STRING);
}
Expand Down