From 8180b09658c2fd95b6bfe3f0b5f3537ba495ba11 Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Fri, 25 Aug 2023 10:55:20 +0200 Subject: [PATCH 1/2] Improve bean qualifiers --- .../micronaut/context/DefaultBeanContext.java | 113 +++++++++-------- .../java/io/micronaut/context/Qualifier.java | 38 ++++++ .../io/micronaut/context/SingletonScope.java | 5 +- .../AnnotationMetadataQualifier.java | 38 +++--- .../qualifiers/AnnotationQualifier.java | 35 +++--- .../AnnotationStereotypeQualifier.java | 7 +- .../inject/qualifiers/AnyQualifier.java | 18 ++- .../inject/qualifiers/CompositeQualifier.java | 22 ++-- .../ExactTypeArgumentNameQualifier.java | 24 ++-- .../FilteringCompositeQualifier.java | 106 ++++++++++++++++ .../inject/qualifiers/FilteringQualifier.java | 66 ++++++++++ .../InterceptorBindingQualifier.java | 114 ++++++++---------- .../inject/qualifiers/NameQualifier.java | 61 +++++----- .../NamedAnnotationStereotypeQualifier.java | 8 +- .../inject/qualifiers/NoneQualifier.java | 17 +-- .../inject/qualifiers/PrimaryQualifier.java | 22 ++-- .../inject/qualifiers/Qualifiers.java | 11 +- .../RepeatableAnnotationQualifier.java | 20 ++- .../qualifiers/TypeAnnotationQualifier.java | 10 +- .../qualifiers/TypeArgumentQualifier.java | 24 ++-- 20 files changed, 488 insertions(+), 271 deletions(-) create mode 100644 inject/src/main/java/io/micronaut/inject/qualifiers/FilteringCompositeQualifier.java create mode 100644 inject/src/main/java/io/micronaut/inject/qualifiers/FilteringQualifier.java diff --git a/inject/src/main/java/io/micronaut/context/DefaultBeanContext.java b/inject/src/main/java/io/micronaut/context/DefaultBeanContext.java index 9d3792ea297..563004c545e 100644 --- a/inject/src/main/java/io/micronaut/context/DefaultBeanContext.java +++ b/inject/src/main/java/io/micronaut/context/DefaultBeanContext.java @@ -112,6 +112,7 @@ import io.micronaut.inject.provider.AbstractProviderDefinition; import io.micronaut.inject.proxy.InterceptedBeanProxy; import io.micronaut.inject.qualifiers.AnyQualifier; +import io.micronaut.inject.qualifiers.FilteringQualifier; import io.micronaut.inject.qualifiers.Qualified; import io.micronaut.inject.qualifiers.Qualifiers; import io.micronaut.inject.validation.BeanDefinitionValidator; @@ -132,6 +133,7 @@ import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.ListIterator; import java.util.Map; @@ -793,7 +795,7 @@ public Collection> getBeanDefinitions(Argument beanType Objects.requireNonNull(beanType, "Bean type cannot be null"); Collection> candidates = findBeanCandidatesInternal(null, beanType); if (qualifier != null) { - candidates = qualifier.reduce(beanType.getType(), candidates.stream()).toList(); + candidates = qualifier.filter(beanType.getType(), candidates); } return Collections.unmodifiableCollection(candidates); } @@ -1531,25 +1533,46 @@ public Collection> getBeanDefinitions(@Nullable Qualifier reduced = qualifier.reduce(Object.class, beanDefinitionsClasses.stream() - .filter(p -> p.isReferenceEnabled(this)) - .map(BeanDefinitionProducer::getReference)); - Stream candidateStream = qualifier.reduce(Object.class, - reduced - .map(ref -> ref.load(this)) - .filter(candidate -> candidate.isEnabled(this)) + if (beanDefinitionsClasses.isEmpty()) { + return Collections.emptyList(); + } + Collection> candidates; + if (qualifier instanceof FilteringQualifier filteringQualifier) { + List> bdCandidates = new ArrayList<>(20); + for (BeanDefinitionProducer producer : beanDefinitionsClasses) { + if (!producer.isReferenceEnabled(this)) { + continue; + } + BeanDefinitionReference reference = producer.getReference(); + if (!filteringQualifier.isQualifies(Object.class, reference)) { + continue; + } + BeanDefinition beanDefinition = reference.load(this); + if (!beanDefinition.isEnabled(this)) { + continue; + } + if (!filteringQualifier.isQualifies(Object.class, beanDefinition)) { + continue; + } + bdCandidates.add(beanDefinition); + } + candidates = bdCandidates; + } else { + Stream> reduced = qualifier.reduce(Object.class, beanDefinitionsClasses.stream() + .filter(p -> p.isReferenceEnabled(this)) + .map(BeanDefinitionProducer::getReference)); + Stream> candidateStream = qualifier.reduce(Object.class, + reduced + .map(ref -> ref.load(this)) + .filter(candidate -> candidate.isEnabled(this)) ); candidates = candidateStream.collect(Collectors.toList()); - - } else { - return Collections.emptyList(); } - if (CollectionUtils.isNotEmpty(candidates)) { + + if (!candidates.isEmpty()) { filterReplacedBeans(null, candidates); } - return candidates; + return (Collection) candidates; } @SuppressWarnings("unchecked") @@ -2588,16 +2611,14 @@ private boolean qualifiedByQualifier(BeanDefinition definitionToBeReplace @SuppressWarnings("unchecked") final Class qualifierClass = (Class) qualifier.getType().orElse(null); if (qualifierClass != null && !qualifierClass.isAssignableFrom(Annotation.class)) { - return Qualifiers.byStereotype(qualifierClass).qualify(replacedBeanType, Stream.of(definitionToBeReplaced)) - .isPresent(); + return Qualifiers.byStereotype(qualifierClass).isQualifies(replacedBeanType, definitionToBeReplaced); } else { throw new ConfigurationException(String.format("Default qualifier value was used while replacing %s", replacedBeanType)); } } - private boolean qualifiedByNamed(BeanType definitionToBeReplaced, Class replacedBeanType, String named) { - return Qualifiers.byName(named).qualify(replacedBeanType, Stream.of(definitionToBeReplaced)) - .isPresent(); + private boolean qualifiedByNamed(BeanType definitionToBeReplaced, Class replacedBeanType, String named) { + return Qualifiers.byName(named).isQualifies(replacedBeanType, definitionToBeReplaced); } private Class getCanonicalBeanType(BeanDefinition beanDefinition) { @@ -2808,7 +2829,7 @@ protected String resolveDisabledBeanMessage(BeanResolutionContext resolutio if (disabledMessage == null) { - Set> beanDefinitions = collectBeanCandidates( + Collection> beanDefinitions = collectBeanCandidates( resolutionContext, beanType, false, @@ -2816,9 +2837,7 @@ protected String resolveDisabledBeanMessage(BeanResolutionContext resolutio disabledBeans.values() ); if (qualifier != null) { - beanDefinitions = qualifier - .reduce(beanType.getType(), beanDefinitions.stream()) - .collect(Collectors.toSet()); + beanDefinitions = qualifier.filter(beanType.getType(), beanDefinitions); } if (!beanDefinitions.isEmpty()) { @@ -3143,8 +3162,7 @@ private Optional> pickOneBean( LOG.debug("Qualifying bean [{}] for qualifier: {} ", beanType.getName(), qualifier); } - Stream> qualified = qualifier.reduce(beanType.getType(), candidates.stream()); - List> beanDefinitionList = qualified.toList(); + Collection> beanDefinitionList = qualifier.filter(beanType.getType(), candidates); if (beanDefinitionList.isEmpty()) { if (LOG.isDebugEnabled()) { LOG.debug("No qualifying beans of type [{}] found for qualifier: {} ", beanType.getName(), qualifier); @@ -3416,11 +3434,10 @@ public Collection> getBeanRegistrations(@Nullable BeanRe Collection> beanDefinitions = findBeanCandidatesInternal(resolutionContext, beanType); if (!beanDefinitions.isEmpty()) { - Stream> candidateStream = applyBeanResolutionFilters(resolutionContext, beanDefinitions.stream()); + beanDefinitions = applyBeanResolutionFilters(resolutionContext, beanDefinitions); if (qualifier != null) { - candidateStream = qualifier.reduce(beanType.getType(), candidateStream); + beanDefinitions = qualifier.filter(beanType.getType(), beanDefinitions); } - beanDefinitions = candidateStream.toList(); } Collection> beanRegistrations; @@ -3472,7 +3489,7 @@ private Collection> resolveBeanRegistrations(BeanResolut } addCandidateToList(resolutionContext, definition, beanType, qualifier, beansOfTypeList); } - if (beansOfTypeList != Collections.EMPTY_SET) { + if (!beansOfTypeList.isEmpty()) { if (Ordered.class.isAssignableFrom(beanType.getType())) { return beansOfTypeList.stream().sorted(OrderUtil.COMPARATOR).toList(); } @@ -3493,22 +3510,26 @@ private void logResolvedExistingBeanRegistrations(Argument beanType, Qual } } - private Stream> applyBeanResolutionFilters(@Nullable BeanResolutionContext resolutionContext, Stream> candidateStream) { + private Collection> applyBeanResolutionFilters(@Nullable BeanResolutionContext resolutionContext, Collection> candidates) { BeanResolutionContext.Segment segment = resolutionContext != null ? resolutionContext.getPath().peek() : null; + BeanDefinition declaringBean = null; + Class proxyTargetDefinitionType = null; if (segment instanceof AbstractBeanResolutionContext.ConstructorSegment || segment instanceof AbstractBeanResolutionContext.MethodSegment) { - BeanDefinition declaringBean = segment.getDeclaringType(); + declaringBean = segment.getDeclaringType(); // if the currently injected segment is a constructor argument and the type to be constructed is the // same as the candidate, then filter out the candidate to avoid a circular injection problem - candidateStream = candidateStream.filter(c -> { - if (c.equals(declaringBean)) { - return false; - } else if (declaringBean instanceof ProxyBeanDefinition proxyBeanDefinition) { - return !proxyBeanDefinition.getTargetDefinitionType().equals(c.getClass()); - } - return true; - }); + if (declaringBean instanceof ProxyBeanDefinition proxyBeanDefinition) { + proxyTargetDefinitionType = proxyBeanDefinition.getTargetDefinitionType(); + } + } + candidates = new LinkedHashSet<>(candidates); // Make mutable + for (Iterator> iterator = candidates.iterator(); iterator.hasNext(); ) { + BeanDefinition c = iterator.next(); + if (c.isAbstract() || declaringBean != null && c.equals(declaringBean) || proxyTargetDefinitionType != null && proxyTargetDefinitionType.equals(c.getClass())) { + iterator.remove(); + } } - return candidateStream.filter(c -> !c.isAbstract()); + return candidates; } private void addCandidateToList(@Nullable BeanResolutionContext resolutionContext, @@ -3534,8 +3555,7 @@ private void addCandidateToList(@Nullable BeanResolutionContext resolutionCo if (container instanceof Object[] array) { container = Arrays.asList(array); } - if (container instanceof Iterable) { - Iterable iterable = (Iterable) container; + if (container instanceof Iterable iterable) { int i = 0; for (Object o : iterable) { if (o == null || !beanType.isInstance(o)) { @@ -3559,11 +3579,10 @@ private boolean isCandidatePresent(Argument beanType, Qualifier qualif final Collection> candidates = findBeanCandidates(null, beanType, true, null); if (!candidates.isEmpty()) { filterReplacedBeans(null, candidates); - Stream> stream = candidates.stream(); - if (qualifier != null && !(qualifier instanceof AnyQualifier)) { - stream = qualifier.reduce(beanType.getType(), stream); + if (qualifier != null) { + return qualifier.isQualifies(beanType.getType(), candidates); } - return stream.findAny().isPresent(); + return true; } return false; } diff --git a/inject/src/main/java/io/micronaut/context/Qualifier.java b/inject/src/main/java/io/micronaut/context/Qualifier.java index 2433c8b248f..624cfaf4286 100644 --- a/inject/src/main/java/io/micronaut/context/Qualifier.java +++ b/inject/src/main/java/io/micronaut/context/Qualifier.java @@ -18,6 +18,7 @@ import io.micronaut.context.annotation.Primary; import io.micronaut.inject.BeanType; +import java.util.Collection; import java.util.Optional; import java.util.stream.Stream; @@ -65,4 +66,41 @@ default boolean contains(Qualifier qualifier) { default > Optional qualify(Class beanType, Stream candidates) { return reduce(beanType, candidates).findFirst(); } + + /** + * Check if the candidate qualifies. + * + * @param beanType The bean type + * @param candidate The candidate + * @return true if matches + * @since 4.2.0 + */ + default boolean isQualifies(Class beanType, BeanType candidate) { + return reduce(beanType, Stream.of(candidate)).findAny().isPresent(); + } + + /** + * Check if at least one candidate qualifies. + * + * @param beanType The bean type + * @param candidates The candidates + * @return true if qualifies + * @since 4.2.0 + */ + default boolean isQualifies(Class beanType, Collection> candidates) { + return reduce(beanType, candidates.stream()).findAny().isPresent(); + } + + /** + * Filter the candidates. + * + * @param beanType The bean type + * @param candidates The candidates + * @param The bean type subclass + * @return The filtered candidates + * @since 4.2.0 + */ + default > Collection filter(Class beanType, Collection candidates) { + return reduce(beanType, candidates.stream()).toList(); + } } diff --git a/inject/src/main/java/io/micronaut/context/SingletonScope.java b/inject/src/main/java/io/micronaut/context/SingletonScope.java index 021bd14683e..11f2b76c2f8 100644 --- a/inject/src/main/java/io/micronaut/context/SingletonScope.java +++ b/inject/src/main/java/io/micronaut/context/SingletonScope.java @@ -30,7 +30,6 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Stream; /** * The singleton scope implementation. @@ -146,8 +145,8 @@ Collection getBeanRegistrations() { Collection> getBeanRegistrations(@NonNull Qualifier qualifier) { List> beanRegistrations = new ArrayList<>(); for (BeanRegistration beanRegistration : singletonByBeanDefinition.values()) { - BeanDefinition beanDefinition = beanRegistration.beanDefinition; - if (qualifier.reduce(beanDefinition.getBeanType(), Stream.of(beanDefinition)).findFirst().isPresent()) { + BeanDefinition beanDefinition = (BeanDefinition) beanRegistration.beanDefinition; + if (((Qualifier) qualifier).isQualifies(beanDefinition.getBeanType(), beanDefinition)) { beanRegistrations.add(beanRegistration); } } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationMetadataQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationMetadataQualifier.java index 472606db56f..81e14fdf8b0 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationMetadataQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationMetadataQualifier.java @@ -38,7 +38,6 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.Stream; /** * A {@link io.micronaut.context.Qualifier} that uses {@link AnnotationMetadata}. @@ -48,7 +47,7 @@ * @since 1.0 */ @Internal -final class AnnotationMetadataQualifier implements Qualifier { +final class AnnotationMetadataQualifier extends FilteringQualifier { @NonNull final String annotationName; @@ -93,30 +92,27 @@ static AnnotationMetadataQualifier fromValue(@NonNull } @Override - public > Stream reduce(Class beanType, Stream candidates) { - return candidates.filter(candidate -> { - if (!QualifierUtils.matchType(beanType, candidate)) { - return false; - } - if (QualifierUtils.matchAny(beanType, candidate)) { + public boolean isQualifies(Class beanType, BeanType candidate) { + if (!QualifierUtils.matchType(beanType, candidate)) { + return false; + } + if (QualifierUtils.matchAny(beanType, candidate)) { + return true; + } + if (candidate instanceof BeanDefinition bdCandidate) { + Qualifier candidateDeclaredQualifier = bdCandidate.getDeclaredQualifier(); + if (candidateDeclaredQualifier != null && candidateDeclaredQualifier.contains(this)) { return true; } - if (candidate instanceof BeanDefinition) { - BeanDefinition bdCandidate = (BeanDefinition) candidate; - Qualifier candidateDeclaredQualifier = bdCandidate.getDeclaredQualifier(); - if (candidateDeclaredQualifier != null && candidateDeclaredQualifier.contains(this)) { + if (candidate instanceof DelegatingBeanDefinition) { + if (matchByAnnotationMetadata(candidate)) { return true; } - if (candidate instanceof DelegatingBeanDefinition) { - if (matchByAnnotationMetadata(candidate)) { - return true; - } - } - } else if (matchByAnnotationMetadata(candidate)) { - return true; } - return QualifierUtils.matchByCandidateName(candidate, beanType, annotationSimpleName); - }); + } else if (matchByAnnotationMetadata(candidate)) { + return true; + } + return QualifierUtils.matchByCandidateName(candidate, beanType, annotationSimpleName); } private > boolean matchByAnnotationMetadata(BT candidate) { diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationQualifier.java index f6f460f5445..0096ef6961e 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationQualifier.java @@ -15,12 +15,10 @@ */ package io.micronaut.inject.qualifiers; -import io.micronaut.context.Qualifier; import io.micronaut.core.annotation.Internal; import io.micronaut.inject.BeanType; import java.lang.annotation.Annotation; -import java.util.stream.Stream; /** * Qualifies using an annotation. @@ -30,33 +28,32 @@ * @since 1.0 */ @Internal -class AnnotationQualifier implements Qualifier { +class AnnotationQualifier extends FilteringQualifier { final Annotation annotation; - + private String qualifiedName; + private String annotationSimpleName; /** * @param annotation The qualifier */ AnnotationQualifier(Annotation annotation) { this.annotation = annotation; + this.qualifiedName = annotation.annotationType().getName(); + this.annotationSimpleName = annotation.annotationType().getSimpleName(); } @Override - public > Stream reduce(Class beanType, Stream candidates) { - String qualifiedName = annotation.annotationType().getName(); - String annotationSimpleName = annotation.annotationType().getSimpleName(); - return candidates.filter(candidate -> { - if (!QualifierUtils.matchType(beanType, candidate)) { - return false; - } - if (QualifierUtils.matchAny(beanType, candidate)) { - return true; - } - if (candidate.getAnnotationMetadata().hasDeclaredAnnotation(qualifiedName)) { - return true; - } - return QualifierUtils.matchByCandidateName(candidate, beanType, annotationSimpleName); - }); + public boolean isQualifies(Class beanType, BeanType candidate) { + if (!QualifierUtils.matchType(beanType, candidate)) { + return false; + } + if (QualifierUtils.matchAny(beanType, candidate)) { + return true; + } + if (candidate.getAnnotationMetadata().hasDeclaredAnnotation(qualifiedName)) { + return true; + } + return QualifierUtils.matchByCandidateName(candidate, beanType, annotationSimpleName); } @Override diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationStereotypeQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationStereotypeQualifier.java index 1b079356c40..ce538e5eb88 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationStereotypeQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationStereotypeQualifier.java @@ -20,7 +20,6 @@ import io.micronaut.inject.BeanType; import java.lang.annotation.Annotation; -import java.util.stream.Stream; /** * A {@link Qualifier} that qualifies based on a bean stereotype. @@ -30,7 +29,7 @@ * @since 1.0 */ @Internal -final class AnnotationStereotypeQualifier implements Qualifier { +final class AnnotationStereotypeQualifier extends FilteringQualifier { final Class stereotype; @@ -42,8 +41,8 @@ final class AnnotationStereotypeQualifier implements Qualifier { } @Override - public > Stream reduce(Class beanType, Stream candidates) { - return candidates.filter(candidate -> candidate.getAnnotationMetadata().hasStereotype(stereotype)); + public boolean isQualifies(Class beanType, BeanType candidate) { + return candidate.getAnnotationMetadata().hasStereotype(stereotype); } @Override diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/AnyQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/AnyQualifier.java index 520f3f913a6..7fc8ab31929 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/AnyQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/AnyQualifier.java @@ -19,6 +19,7 @@ import io.micronaut.core.annotation.Internal; import io.micronaut.inject.BeanType; +import java.util.Collection; import java.util.Optional; import java.util.stream.Stream; @@ -29,13 +30,18 @@ * @since 3.0.0 */ @Internal -public final class AnyQualifier implements Qualifier { +public final class AnyQualifier extends FilteringQualifier { @SuppressWarnings("rawtypes") public static final AnyQualifier INSTANCE = new AnyQualifier(); private AnyQualifier() { } + @Override + public boolean isQualifies(Class beanType, BeanType candidate) { + return true; + } + @Override public > Stream reduce(Class beanType, Stream candidates) { return candidates; @@ -51,6 +57,16 @@ public > Optional qualify(Class beanType, Stream beanType, Collection> candidates) { + return !candidates.isEmpty(); + } + + @Override + public > Collection filter(Class beanType, Collection candidates) { + return candidates; + } + @Override public String toString() { return "@Any"; diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/CompositeQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/CompositeQualifier.java index 84c5e8aa6bb..81188ab2133 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/CompositeQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/CompositeQualifier.java @@ -33,39 +33,47 @@ @Internal final class CompositeQualifier implements Qualifier { - private final Qualifier[] qualifiers; + private final Qualifier[] qualifiers; /** * @param qualifiers The qualifiers */ - CompositeQualifier(Qualifier... qualifiers) { + CompositeQualifier(Qualifier[] qualifiers) { this.qualifiers = qualifiers; } @Override public > Stream reduce(Class beanType, Stream candidates) { Stream reduced = candidates; - for (Qualifier qualifier : qualifiers) { + for (Qualifier qualifier : qualifiers) { reduced = qualifier.reduce(beanType, reduced); } return reduced; } - public Qualifier[] getQualifiers() { + public Qualifier[] getQualifiers() { return qualifiers; } @Override public boolean contains(Qualifier qualifier) { - if (qualifier instanceof CompositeQualifier) { - for (Qualifier q : ((CompositeQualifier) qualifier).qualifiers) { + if (qualifier instanceof CompositeQualifier compositeQualifier) { + for (Qualifier q : compositeQualifier.qualifiers) { if (!contains(q)) { return false; } } return true; } - for (Qualifier q : qualifiers) { + if (qualifier instanceof FilteringCompositeQualifier filteringCompositeQualifier) { + for (Qualifier q : filteringCompositeQualifier.getQualifiers()) { + if (!contains(q)) { + return false; + } + } + return true; + } + for (Qualifier q : qualifiers) { if (q.contains(qualifier)) { return true; } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/ExactTypeArgumentNameQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/ExactTypeArgumentNameQualifier.java index b9cd3fd8ec7..f5e3138ebac 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/ExactTypeArgumentNameQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/ExactTypeArgumentNameQualifier.java @@ -15,7 +15,6 @@ */ package io.micronaut.inject.qualifiers; -import io.micronaut.context.Qualifier; import io.micronaut.core.reflect.ClassUtils; import io.micronaut.core.reflect.GenericTypeUtils; import io.micronaut.core.type.Argument; @@ -28,7 +27,6 @@ import java.util.List; import java.util.Objects; import java.util.stream.Collectors; -import java.util.stream.Stream; /** * Qualifies by the exact type argument name. Useful for qualifying when inheritance is not a factory such as by annotation. @@ -37,7 +35,7 @@ * @since 3.0.0 * @author graemerocher */ -final class ExactTypeArgumentNameQualifier implements Qualifier { +final class ExactTypeArgumentNameQualifier extends FilteringQualifier { private static final Logger LOG = ClassUtils.getLogger(TypeArgumentQualifier.class); private final String typeName; @@ -46,17 +44,17 @@ final class ExactTypeArgumentNameQualifier implements Qualifier { } @Override - public > Stream reduce(Class beanType, Stream candidates) { - return candidates.filter(candidate -> beanType.isAssignableFrom(candidate.getBeanType())) - .filter(candidate -> { - final List> typeArguments = getTypeArguments(beanType, candidate); - boolean result = areTypesCompatible(typeArguments); - if (LOG.isTraceEnabled() && !result) { - LOG.trace("Bean type {} is not compatible with candidate generic types [{}] of candidate {}", beanType, CollectionUtils.toString(typeArguments), candidate); - } + public boolean isQualifies(Class beanType, BeanType candidate) { + if (!beanType.isAssignableFrom(candidate.getBeanType())) { + return false; + } + final List> typeArguments = getTypeArguments(beanType, candidate); + boolean result = areTypesCompatible(typeArguments); + if (LOG.isTraceEnabled() && !result) { + LOG.trace("Bean type {} is not compatible with candidate generic types [{}] of candidate {}", beanType, CollectionUtils.toString(typeArguments), candidate); + } - return result; - }); + return result; } private boolean areTypesCompatible(List> typeArguments) { diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/FilteringCompositeQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/FilteringCompositeQualifier.java new file mode 100644 index 00000000000..2d65196b2b8 --- /dev/null +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/FilteringCompositeQualifier.java @@ -0,0 +1,106 @@ +/* + * Copyright 2017-2023 original authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micronaut.inject.qualifiers; + +import io.micronaut.context.Qualifier; +import io.micronaut.core.annotation.Internal; +import io.micronaut.inject.BeanType; + +import java.util.Arrays; +import java.util.stream.Collectors; + +/** + * A {@link Qualifier} composed of other qualifiers. + * + * @param The type + * @author Graeme Rocher + * @since 1.0 + */ +@Internal +final class FilteringCompositeQualifier extends FilteringQualifier { + + private final FilteringQualifier[] qualifiers; + + /** + * @param qualifiers The qualifiers + */ + FilteringCompositeQualifier(FilteringQualifier[] qualifiers) { + this.qualifiers = qualifiers; + } + + @Override + public boolean isQualifies(Class beanType, BeanType candidate) { + for (FilteringQualifier qualifier : qualifiers) { + if (!qualifier.isQualifies(beanType, candidate)) { + return false; + } + } + return true; + } + + public FilteringQualifier[] getQualifiers() { + return qualifiers; + } + + @Override + public boolean contains(Qualifier qualifier) { + if (qualifier instanceof FilteringCompositeQualifier filteringCompositeQualifier) { + for (Qualifier q : filteringCompositeQualifier.qualifiers) { + if (!contains(q)) { + return false; + } + } + return true; + } + if (qualifier instanceof CompositeQualifier compositeQualifier) { + for (Qualifier q : compositeQualifier.getQualifiers()) { + if (!contains(q)) { + return false; + } + } + return true; + } + for (FilteringQualifier q : qualifiers) { + if (q.contains(qualifier)) { + return true; + } + } + return false; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + FilteringCompositeQualifier that = (FilteringCompositeQualifier) o; + return Arrays.equals(qualifiers, that.qualifiers); + } + + @Override + public int hashCode() { + return Arrays.hashCode(qualifiers); + } + + @Override + public String toString() { + return Arrays.stream(qualifiers).map(Object::toString).collect(Collectors.joining(" and ")); + } +} diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/FilteringQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/FilteringQualifier.java new file mode 100644 index 00000000000..f4fbdc42191 --- /dev/null +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/FilteringQualifier.java @@ -0,0 +1,66 @@ +/* + * Copyright 2017-2023 original authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micronaut.inject.qualifiers; + +import io.micronaut.context.Qualifier; +import io.micronaut.core.annotation.Internal; +import io.micronaut.inject.BeanType; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.stream.Stream; + +/** + * A variation of {@link Qualifier} that is a simple filter. + * + * @param The qualifier type + * @author Denis Stepanov + * @since 4.2.0 + */ +@Internal +public abstract class FilteringQualifier implements Qualifier { + + @Override + public > Stream reduce(Class beanType, Stream candidates) { + return candidates.filter(candidate -> isQualifies(beanType, candidate)); + } + + @Override + public boolean isQualifies(Class beanType, Collection> candidates) { + for (BeanType candidate : candidates) { + if (isQualifies(beanType, candidate)) { + return true; + } + } + return false; + } + + @Override + public > Collection filter(Class beanType, Collection candidates) { + int size = candidates.size(); + if (size == 1) { + return isQualifies(beanType, candidates.iterator().next()) ? candidates : Collections.emptyList(); + } + Collection result = new ArrayList<>(size); + for (BT candidate : candidates) { + if (isQualifies(beanType, candidate)) { + result.add(candidate); + } + } + return result; + } +} diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/InterceptorBindingQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/InterceptorBindingQualifier.java index 35dd4568d16..b98a1609dc0 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/InterceptorBindingQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/InterceptorBindingQualifier.java @@ -15,7 +15,6 @@ */ package io.micronaut.inject.qualifiers; -import io.micronaut.context.Qualifier; import io.micronaut.core.annotation.AnnotationMetadata; import io.micronaut.core.annotation.AnnotationUtil; import io.micronaut.core.annotation.AnnotationValue; @@ -34,7 +33,6 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.Stream; /** * Qualifier used to resolve the interceptor binding when injection method interceptors for AOP. @@ -44,7 +42,7 @@ * @since 2.4.0 */ @Internal -public final class InterceptorBindingQualifier implements Qualifier { +public final class InterceptorBindingQualifier extends FilteringQualifier { public static final String META_BINDING_VALUES = "$bindingValues"; private static final String META_MEMBER_INTERCEPTOR_TYPE = "interceptorType"; private final Map>> supportedAnnotationNames; @@ -99,64 +97,62 @@ private static Map>> findSupportedAnnotations(Co } @Override - public > Stream reduce(Class beanType, Stream candidates) { - return candidates.filter(candidate -> { - if (supportedInterceptorTypes.contains(candidate.getBeanType())) { - return true; - } - final AnnotationMetadata annotationMetadata = candidate.getAnnotationMetadata(); - Collection> interceptorValues = resolveInterceptorAnnotationValues(annotationMetadata, null); - if (interceptorValues.isEmpty()) { + public boolean isQualifies(Class beanType, BeanType candidate) { + if (supportedInterceptorTypes.contains(candidate.getBeanType())) { + return true; + } + final AnnotationMetadata annotationMetadata = candidate.getAnnotationMetadata(); + Collection> interceptorValues = resolveInterceptorAnnotationValues(annotationMetadata, null); + if (interceptorValues.isEmpty()) { + return false; + } + if (interceptorValues.size() == 1) { + // single binding case, fast path + final AnnotationValue interceptorBinding = interceptorValues.iterator().next(); + final String annotationName = interceptorBinding.stringValue().orElse(null); + if (annotationName == null) { return false; } - if (interceptorValues.size() == 1) { - // single binding case, fast path - final AnnotationValue interceptorBinding = interceptorValues.iterator().next(); - final String annotationName = interceptorBinding.stringValue().orElse(null); + final List> bindingList = supportedAnnotationNames.get(annotationName); + if (bindingList != null) { + final AnnotationValue otherBinding = + interceptorBinding.getAnnotation(META_BINDING_VALUES).orElse(null); + boolean matched = true; + for (AnnotationValue binding : bindingList) { + matched = matched && (!binding.isPresent(META_BINDING_VALUES) || binding.equals(otherBinding)); + } + return matched; + } else { + return supportedAnnotationNames.containsKey(annotationName); + } + } else { + // multiple binding case + boolean matched = false; + for (AnnotationValue annotation : interceptorValues) { + final String annotationName = annotation.stringValue().orElse(null); if (annotationName == null) { - return false; + continue; } final List> bindingList = supportedAnnotationNames.get(annotationName); if (bindingList != null) { final AnnotationValue otherBinding = - interceptorBinding.getAnnotation(META_BINDING_VALUES).orElse(null); - boolean matched = true; + annotation.getAnnotation(META_BINDING_VALUES).orElse(null); for (AnnotationValue binding : bindingList) { - matched = matched && (!binding.isPresent(META_BINDING_VALUES) || binding.equals(otherBinding)); + matched = (!binding.isPresent(META_BINDING_VALUES) || binding.equals(otherBinding)); + if (matched) { + break; + } } - return matched; } else { - return supportedAnnotationNames.containsKey(annotationName); + matched = supportedAnnotationNames.containsKey(annotationName); } - } else { - // multiple binding case - boolean matched = false; - for (AnnotationValue annotation : interceptorValues) { - final String annotationName = annotation.stringValue().orElse(null); - if (annotationName == null) { - continue; - } - final List> bindingList = supportedAnnotationNames.get(annotationName); - if (bindingList != null) { - final AnnotationValue otherBinding = - annotation.getAnnotation(META_BINDING_VALUES).orElse(null); - for (AnnotationValue binding : bindingList) { - matched = (!binding.isPresent(META_BINDING_VALUES) || binding.equals(otherBinding)); - if (matched) { - break; - } - } - } else { - matched = supportedAnnotationNames.containsKey(annotationName); - } - if (matched) { - break; - } + if (matched) { + break; } - return matched; } - }); + return matched; + } } @Override @@ -193,19 +189,15 @@ public String toString() { if (CollectionUtils.isEmpty(bindings)) { return Collections.emptyList(); } - return bindings - .stream() - .filter(av -> { - if (av.stringValue().isEmpty()) { - return false; - } - if (kind == null) { - return true; - } else { - final String specifiedkind = av.stringValue("kind").orElse(null); - return specifiedkind == null || specifiedkind.equals(kind); - } - }) - .toList(); + List> result = new ArrayList<>(bindings.size()); + for (AnnotationValue av : bindings) { + if (av.stringValue().isEmpty()) { + continue; + } + if (kind == null || av.stringValue("kind").orElse(kind).equals(kind)) { + result.add(av); + } + } + return result; } } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/NameQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/NameQualifier.java index 003ca24d4d5..c42ebec5782 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/NameQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/NameQualifier.java @@ -27,9 +27,6 @@ import java.lang.annotation.Annotation; import java.util.Objects; import java.util.Optional; -import java.util.stream.Stream; - -import static io.micronaut.core.util.ArgumentUtils.check; /** * Qualifies using a name. @@ -39,7 +36,7 @@ * @since 1.0 */ @Internal -class NameQualifier implements Qualifier, io.micronaut.core.naming.Named { +class NameQualifier extends FilteringQualifier implements io.micronaut.core.naming.Named { protected final Class annotationType; private final String name; @@ -55,39 +52,35 @@ class NameQualifier implements Qualifier, io.micronaut.core.naming.Named { } @Override - public > Stream reduce(Class beanType, Stream candidates) { - check("beanType", beanType).notNull(); - check("candidates", candidates).notNull(); - return candidates.filter(candidate -> { - if (!QualifierUtils.matchType(beanType, candidate)) { - return false; - } - if (QualifierUtils.matchAny(beanType, candidate)) { + public boolean isQualifies(Class beanType, BeanType candidate) { + if (!QualifierUtils.matchType(beanType, candidate)) { + return false; + } + if (QualifierUtils.matchAny(beanType, candidate)) { + return true; + } + AnnotationMetadata annotationMetadata = candidate.getAnnotationMetadata(); + // here we resolved the declared Qualifier of the bean + String thisName = annotationMetadata + .findDeclaredAnnotation(AnnotationUtil.NAMED) + .flatMap(AnnotationValue::stringValue) + .orElse(null); + + if (thisName == null && candidate instanceof BeanDefinition beanDefinition) { + Qualifier qualifier = beanDefinition.getDeclaredQualifier(); + if (qualifier != null && qualifier.contains(this)) { return true; } - AnnotationMetadata annotationMetadata = candidate.getAnnotationMetadata(); - // here we resolved the declared Qualifier of the bean - String thisName = annotationMetadata - .findDeclaredAnnotation(AnnotationUtil.NAMED) - .flatMap(AnnotationValue::stringValue) - .orElse(null); - - if (thisName == null && candidate instanceof BeanDefinition) { - Qualifier qualifier = ((BeanDefinition) candidate).getDeclaredQualifier(); - if (qualifier != null && qualifier.contains((Qualifier) this)) { - return true; - } - } - if (thisName == null) { - if (candidate instanceof NameResolver) { - Optional resolvedName = ((NameResolver) candidate).resolveName(); - thisName = resolvedName.orElse(candidate.getBeanType().getSimpleName()); - } else { - thisName = candidate.getBeanType().getSimpleName(); - } + } + if (thisName == null) { + if (candidate instanceof NameResolver) { + Optional resolvedName = ((NameResolver) candidate).resolveName(); + thisName = resolvedName.orElse(candidate.getBeanType().getSimpleName()); + } else { + thisName = candidate.getBeanType().getSimpleName(); } - return thisName.equalsIgnoreCase(name) || thisName.equalsIgnoreCase(name + beanType.getSimpleName()); - }); + } + return thisName.equalsIgnoreCase(name) || thisName.equalsIgnoreCase(name + beanType.getSimpleName()); } @Override diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/NamedAnnotationStereotypeQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/NamedAnnotationStereotypeQualifier.java index ed720e6851f..7ac366f775c 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/NamedAnnotationStereotypeQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/NamedAnnotationStereotypeQualifier.java @@ -15,12 +15,10 @@ */ package io.micronaut.inject.qualifiers; -import io.micronaut.context.Qualifier; import io.micronaut.core.annotation.Internal; import io.micronaut.inject.BeanType; import java.util.Objects; -import java.util.stream.Stream; /** * Qualifiers for a named stereotype. @@ -29,7 +27,7 @@ * @author graemerocher */ @Internal -final class NamedAnnotationStereotypeQualifier implements Qualifier { +final class NamedAnnotationStereotypeQualifier extends FilteringQualifier { final String stereotype; @@ -41,8 +39,8 @@ final class NamedAnnotationStereotypeQualifier implements Qualifier { } @Override - public > Stream reduce(Class beanType, Stream candidates) { - return candidates.filter(candidate -> candidate.getAnnotationMetadata().hasStereotype(stereotype)); + public boolean isQualifies(Class beanType, BeanType candidate) { + return candidate.getAnnotationMetadata().hasStereotype(stereotype); } @Override diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/NoneQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/NoneQualifier.java index 66eefe43ed1..311e97e44db 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/NoneQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/NoneQualifier.java @@ -15,14 +15,11 @@ */ package io.micronaut.inject.qualifiers; -import io.micronaut.context.Qualifier; import io.micronaut.core.annotation.AnnotationUtil; import io.micronaut.core.annotation.Internal; import io.micronaut.inject.BeanDefinition; import io.micronaut.inject.BeanType; -import java.util.stream.Stream; - /** * A qualifier to lookup beans without any qualifier. * @@ -30,7 +27,7 @@ * @since 3.8.0 */ @Internal -final class NoneQualifier implements Qualifier { +final class NoneQualifier extends FilteringQualifier { @SuppressWarnings("rawtypes") public static final NoneQualifier INSTANCE = new NoneQualifier(); @@ -38,13 +35,11 @@ private NoneQualifier() { } @Override - public > Stream reduce(Class beanType, Stream candidates) { - return candidates.filter(candidate -> { - if (candidate instanceof BeanDefinition) { - return ((BeanDefinition) candidate).getDeclaredQualifier() == null; - } - return !AnnotationUtil.hasDeclaredQualifierAnnotation(candidate.getAnnotationMetadata()); - }); + public boolean isQualifies(Class beanType, BeanType candidate) { + if (candidate instanceof BeanDefinition beanDefinition) { + return beanDefinition.getDeclaredQualifier() == null; + } + return !AnnotationUtil.hasDeclaredQualifierAnnotation(candidate.getAnnotationMetadata()); } @Override diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/PrimaryQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/PrimaryQualifier.java index 0559d5c15dd..6fbca01bbe0 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/PrimaryQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/PrimaryQualifier.java @@ -19,8 +19,6 @@ import io.micronaut.core.annotation.Internal; import io.micronaut.inject.BeanType; -import java.util.stream.Stream; - /** * A qualifier to lookup a primary bean. * @@ -30,7 +28,7 @@ */ @Internal @SuppressWarnings("java:S1845") -public final class PrimaryQualifier implements Qualifier { +public final class PrimaryQualifier extends FilteringQualifier { @SuppressWarnings({"rawtypes", "java:S1845"}) public static final PrimaryQualifier INSTANCE = new PrimaryQualifier(); @@ -39,16 +37,14 @@ private PrimaryQualifier() { } @Override - public > Stream reduce(Class beanType, Stream candidates) { - return candidates.filter(candidate -> { - if (!QualifierUtils.matchType(beanType, candidate)) { - return false; - } - if (QualifierUtils.matchAny(beanType, candidate)) { - return true; - } - return candidate.isPrimary() || QualifierUtils.matchByCandidateName(candidate, beanType, Qualifier.PRIMARY); - }); + public boolean isQualifies(Class beanType, BeanType candidate) { + if (!QualifierUtils.matchType(beanType, candidate)) { + return false; + } + if (QualifierUtils.matchAny(beanType, candidate)) { + return true; + } + return candidate.isPrimary() || QualifierUtils.matchByCandidateName(candidate, beanType, Qualifier.PRIMARY); } @Override diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/Qualifiers.java b/inject/src/main/java/io/micronaut/inject/qualifiers/Qualifiers.java index 1283b067942..e39878c023c 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/Qualifiers.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/Qualifiers.java @@ -115,7 +115,16 @@ Qualifier forArgument(@NonNull Argument argument) { * @return The qualifier */ public static Qualifier byQualifiers(Qualifier... qualifiers) { - return new CompositeQualifier<>(qualifiers); + FilteringQualifier[] filteringQualifiers = new FilteringQualifier[qualifiers.length]; + for (int i = 0; i < qualifiers.length; i++) { + Qualifier qualifier = qualifiers[i]; + if (qualifier instanceof FilteringQualifier filteringQualifier) { + filteringQualifiers[i] = filteringQualifier; + } else { + return new CompositeQualifier<>(qualifiers); + } + } + return new FilteringCompositeQualifier<>(filteringQualifiers); } /** diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/RepeatableAnnotationQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/RepeatableAnnotationQualifier.java index 35e99d8c09f..22b0ca6368c 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/RepeatableAnnotationQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/RepeatableAnnotationQualifier.java @@ -15,7 +15,6 @@ */ package io.micronaut.inject.qualifiers; -import io.micronaut.context.Qualifier; import io.micronaut.core.annotation.AnnotationMetadata; import io.micronaut.core.annotation.AnnotationValue; import io.micronaut.core.util.ObjectUtils; @@ -25,7 +24,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.stream.Stream; /** * A qualifier for repeatable annotations. @@ -34,7 +32,7 @@ * @since 3.1.0 * @param The bean type */ -final class RepeatableAnnotationQualifier implements Qualifier { +final class RepeatableAnnotationQualifier extends FilteringQualifier { private final List> repeatableValues; private final String repeatableName; @@ -55,15 +53,13 @@ public String toString() { } @Override - public > Stream reduce(Class beanType, Stream candidates) { - return candidates.filter(candidate -> { - final AnnotationValue declared = candidate.getAnnotationMetadata().getAnnotation(repeatableName); - if (declared != null) { - final List> repeated = declared.getAnnotations(AnnotationMetadata.VALUE_MEMBER); - return repeated.containsAll(repeatableValues); - } - return false; - }); + public boolean isQualifies(Class beanType, BeanType candidate) { + final AnnotationValue declared = candidate.getAnnotationMetadata().getAnnotation(repeatableName); + if (declared != null) { + final List> repeated = declared.getAnnotations(AnnotationMetadata.VALUE_MEMBER); + return repeated.containsAll(repeatableValues); + } + return false; } @Override diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/TypeAnnotationQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/TypeAnnotationQualifier.java index 97450b4688e..dffac216bda 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/TypeAnnotationQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/TypeAnnotationQualifier.java @@ -15,18 +15,16 @@ */ package io.micronaut.inject.qualifiers; -import io.micronaut.context.Qualifier; import io.micronaut.context.annotation.Type; import io.micronaut.core.annotation.Internal; +import io.micronaut.core.annotation.Nullable; import io.micronaut.inject.BeanType; -import io.micronaut.core.annotation.Nullable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; -import java.util.stream.Stream; /** * Implementation of {@link Type} qualifier. @@ -36,7 +34,7 @@ * @since 1.0 */ @Internal -public class TypeAnnotationQualifier implements Qualifier { +public class TypeAnnotationQualifier extends FilteringQualifier { private final List> types; @@ -60,8 +58,8 @@ public class TypeAnnotationQualifier implements Qualifier { } @Override - public > Stream reduce(Class beanType, Stream candidates) { - return candidates.filter(candidate -> areTypesCompatible(candidate.getBeanType())); + public boolean isQualifies(Class beanType, BeanType candidate) { + return areTypesCompatible(candidate.getBeanType()); } @Override diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/TypeArgumentQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/TypeArgumentQualifier.java index 37fbe1b232a..b778333bef2 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/TypeArgumentQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/TypeArgumentQualifier.java @@ -28,7 +28,6 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -import java.util.stream.Stream; /** * A {@link Qualifier} that qualifies beans by generic type arguments. @@ -38,7 +37,7 @@ * @since 1.0 */ @Internal -public class TypeArgumentQualifier implements Qualifier { +public class TypeArgumentQualifier extends FilteringQualifier { private static final Logger LOG = ClassUtils.getLogger(TypeArgumentQualifier.class); private final Class[] typeArguments; @@ -51,18 +50,17 @@ public class TypeArgumentQualifier implements Qualifier { } @Override - public > Stream reduce(Class beanType, Stream candidates) { - return candidates.filter(candidate -> beanType.isAssignableFrom(candidate.getBeanType())) - .filter(candidate -> { - - List> typeArguments = getTypeArguments(beanType, candidate); + public boolean isQualifies(Class beanType, BeanType candidate) { + if (!beanType.isAssignableFrom(candidate.getBeanType())) { + return false; + } + List> typeArguments = getTypeArguments(beanType, candidate); - boolean result = areTypesCompatible(typeArguments); - if (LOG.isTraceEnabled() && !result) { - LOG.trace("Bean type {} is not compatible with candidate generic types [{}] of candidate {}", beanType, CollectionUtils.toString(typeArguments), candidate); - } - return result; - }); + boolean result = areTypesCompatible(typeArguments); + if (LOG.isTraceEnabled() && !result) { + LOG.trace("Bean type {} is not compatible with candidate generic types [{}] of candidate {}", beanType, CollectionUtils.toString(typeArguments), candidate); + } + return result; } /** From 53ca8024351e1d7e9414d533a91e742c95adec26 Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Fri, 25 Aug 2023 11:45:07 +0200 Subject: [PATCH 2/2] Address CR and correct closest type qualifier --- .../micronaut/context/DefaultBeanContext.java | 10 +++--- .../context/DefaultRuntimeBeanDefinition.java | 6 ++++ .../java/io/micronaut/context/Qualifier.java | 4 +-- .../io/micronaut/context/SingletonScope.java | 2 +- .../AnnotationMetadataQualifier.java | 2 +- .../qualifiers/AnnotationQualifier.java | 2 +- .../AnnotationStereotypeQualifier.java | 2 +- .../inject/qualifiers/AnyQualifier.java | 4 +-- .../ClosestTypeArgumentQualifier.java | 31 ++++++++++++++++--- .../ExactTypeArgumentNameQualifier.java | 2 +- .../FilteringCompositeQualifier.java | 4 +-- .../inject/qualifiers/FilteringQualifier.java | 10 +++--- .../InterceptorBindingQualifier.java | 2 +- .../inject/qualifiers/NameQualifier.java | 2 +- .../NamedAnnotationStereotypeQualifier.java | 2 +- .../inject/qualifiers/NoneQualifier.java | 2 +- .../inject/qualifiers/PrimaryQualifier.java | 2 +- .../RepeatableAnnotationQualifier.java | 2 +- .../qualifiers/TypeAnnotationQualifier.java | 2 +- .../qualifiers/TypeArgumentQualifier.java | 8 ++--- 20 files changed, 65 insertions(+), 36 deletions(-) diff --git a/inject/src/main/java/io/micronaut/context/DefaultBeanContext.java b/inject/src/main/java/io/micronaut/context/DefaultBeanContext.java index 563004c545e..06dc9bf1a93 100644 --- a/inject/src/main/java/io/micronaut/context/DefaultBeanContext.java +++ b/inject/src/main/java/io/micronaut/context/DefaultBeanContext.java @@ -1544,14 +1544,14 @@ public Collection> getBeanDefinitions(@Nullable Qualifier reference = producer.getReference(); - if (!filteringQualifier.isQualifies(Object.class, reference)) { + if (!filteringQualifier.doesQualify(Object.class, reference)) { continue; } BeanDefinition beanDefinition = reference.load(this); if (!beanDefinition.isEnabled(this)) { continue; } - if (!filteringQualifier.isQualifies(Object.class, beanDefinition)) { + if (!filteringQualifier.doesQualify(Object.class, beanDefinition)) { continue; } bdCandidates.add(beanDefinition); @@ -2611,14 +2611,14 @@ private boolean qualifiedByQualifier(BeanDefinition definitionToBeReplace @SuppressWarnings("unchecked") final Class qualifierClass = (Class) qualifier.getType().orElse(null); if (qualifierClass != null && !qualifierClass.isAssignableFrom(Annotation.class)) { - return Qualifiers.byStereotype(qualifierClass).isQualifies(replacedBeanType, definitionToBeReplaced); + return Qualifiers.byStereotype(qualifierClass).doesQualify(replacedBeanType, definitionToBeReplaced); } else { throw new ConfigurationException(String.format("Default qualifier value was used while replacing %s", replacedBeanType)); } } private boolean qualifiedByNamed(BeanType definitionToBeReplaced, Class replacedBeanType, String named) { - return Qualifiers.byName(named).isQualifies(replacedBeanType, definitionToBeReplaced); + return Qualifiers.byName(named).doesQualify(replacedBeanType, definitionToBeReplaced); } private Class getCanonicalBeanType(BeanDefinition beanDefinition) { @@ -3580,7 +3580,7 @@ private boolean isCandidatePresent(Argument beanType, Qualifier qualif if (!candidates.isEmpty()) { filterReplacedBeans(null, candidates); if (qualifier != null) { - return qualifier.isQualifies(beanType.getType(), candidates); + return qualifier.doesQualify(beanType.getType(), candidates); } return true; } diff --git a/inject/src/main/java/io/micronaut/context/DefaultRuntimeBeanDefinition.java b/inject/src/main/java/io/micronaut/context/DefaultRuntimeBeanDefinition.java index 55555c161de..22b6d08c86e 100644 --- a/inject/src/main/java/io/micronaut/context/DefaultRuntimeBeanDefinition.java +++ b/inject/src/main/java/io/micronaut/context/DefaultRuntimeBeanDefinition.java @@ -29,6 +29,7 @@ import io.micronaut.core.util.CollectionUtils; import io.micronaut.inject.BeanDefinition; import io.micronaut.inject.annotation.MutableAnnotationMetadata; +import io.micronaut.inject.qualifiers.ClosestTypeArgumentQualifier; import io.micronaut.inject.qualifiers.PrimaryQualifier; import io.micronaut.inject.qualifiers.TypeArgumentQualifier; @@ -252,6 +253,11 @@ public Builder qualifier(Qualifier qualifier) { .map(Argument::of) .toArray(Argument[]::new); typeArguments(arguments); + } else if (qualifier instanceof ClosestTypeArgumentQualifier typeArgumentQualifier) { + Argument[] arguments = Arrays.stream(typeArgumentQualifier.getTypeArguments()) + .map(Argument::of) + .toArray(Argument[]::new); + typeArguments(arguments); } return this; } diff --git a/inject/src/main/java/io/micronaut/context/Qualifier.java b/inject/src/main/java/io/micronaut/context/Qualifier.java index 624cfaf4286..cf8b01a185d 100644 --- a/inject/src/main/java/io/micronaut/context/Qualifier.java +++ b/inject/src/main/java/io/micronaut/context/Qualifier.java @@ -75,7 +75,7 @@ default > Optional qualify(Class beanType, Stream< * @return true if matches * @since 4.2.0 */ - default boolean isQualifies(Class beanType, BeanType candidate) { + default boolean doesQualify(Class beanType, BeanType candidate) { return reduce(beanType, Stream.of(candidate)).findAny().isPresent(); } @@ -87,7 +87,7 @@ default boolean isQualifies(Class beanType, BeanType candidate) { * @return true if qualifies * @since 4.2.0 */ - default boolean isQualifies(Class beanType, Collection> candidates) { + default boolean doesQualify(Class beanType, Collection> candidates) { return reduce(beanType, candidates.stream()).findAny().isPresent(); } diff --git a/inject/src/main/java/io/micronaut/context/SingletonScope.java b/inject/src/main/java/io/micronaut/context/SingletonScope.java index 11f2b76c2f8..fb32a201ca5 100644 --- a/inject/src/main/java/io/micronaut/context/SingletonScope.java +++ b/inject/src/main/java/io/micronaut/context/SingletonScope.java @@ -146,7 +146,7 @@ Collection> getBeanRegistrations(@NonNull Qualifier quali List> beanRegistrations = new ArrayList<>(); for (BeanRegistration beanRegistration : singletonByBeanDefinition.values()) { BeanDefinition beanDefinition = (BeanDefinition) beanRegistration.beanDefinition; - if (((Qualifier) qualifier).isQualifies(beanDefinition.getBeanType(), beanDefinition)) { + if (((Qualifier) qualifier).doesQualify(beanDefinition.getBeanType(), beanDefinition)) { beanRegistrations.add(beanRegistration); } } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationMetadataQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationMetadataQualifier.java index 81e14fdf8b0..11e9b2c0304 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationMetadataQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationMetadataQualifier.java @@ -92,7 +92,7 @@ static AnnotationMetadataQualifier fromValue(@NonNull } @Override - public boolean isQualifies(Class beanType, BeanType candidate) { + public boolean doesQualify(Class beanType, BeanType candidate) { if (!QualifierUtils.matchType(beanType, candidate)) { return false; } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationQualifier.java index 0096ef6961e..104511fe1a3 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationQualifier.java @@ -43,7 +43,7 @@ class AnnotationQualifier extends FilteringQualifier { } @Override - public boolean isQualifies(Class beanType, BeanType candidate) { + public boolean doesQualify(Class beanType, BeanType candidate) { if (!QualifierUtils.matchType(beanType, candidate)) { return false; } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationStereotypeQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationStereotypeQualifier.java index ce538e5eb88..5aaf3903049 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationStereotypeQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/AnnotationStereotypeQualifier.java @@ -41,7 +41,7 @@ final class AnnotationStereotypeQualifier extends FilteringQualifier { } @Override - public boolean isQualifies(Class beanType, BeanType candidate) { + public boolean doesQualify(Class beanType, BeanType candidate) { return candidate.getAnnotationMetadata().hasStereotype(stereotype); } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/AnyQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/AnyQualifier.java index 7fc8ab31929..299d86575c4 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/AnyQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/AnyQualifier.java @@ -38,7 +38,7 @@ private AnyQualifier() { } @Override - public boolean isQualifies(Class beanType, BeanType candidate) { + public boolean doesQualify(Class beanType, BeanType candidate) { return true; } @@ -58,7 +58,7 @@ public > Optional qualify(Class beanType, Stream beanType, Collection> candidates) { + public boolean doesQualify(Class beanType, Collection> candidates) { return !candidates.isEmpty(); } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/ClosestTypeArgumentQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/ClosestTypeArgumentQualifier.java index f7577669536..18e4fbd3931 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/ClosestTypeArgumentQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/ClosestTypeArgumentQualifier.java @@ -15,10 +15,14 @@ */ package io.micronaut.inject.qualifiers; +import io.micronaut.context.Qualifier; import io.micronaut.core.annotation.Internal; import io.micronaut.core.reflect.ClassUtils; +import io.micronaut.core.reflect.GenericTypeUtils; +import io.micronaut.core.type.Argument; import io.micronaut.core.util.CollectionUtils; import io.micronaut.core.util.StreamUtils; +import io.micronaut.inject.BeanDefinition; import io.micronaut.inject.BeanType; import org.slf4j.Logger; @@ -35,22 +39,30 @@ * @since 1.1.1 */ @Internal -public class ClosestTypeArgumentQualifier extends TypeArgumentQualifier { +public final class ClosestTypeArgumentQualifier implements Qualifier { private static final Logger LOG = ClassUtils.getLogger(ClosestTypeArgumentQualifier.class); private final List>[] hierarchies; + private final Class[] typeArguments; /** * @param typeArguments The type arguments */ ClosestTypeArgumentQualifier(Class... typeArguments) { - super(typeArguments); + this.typeArguments = typeArguments; this.hierarchies = new List[typeArguments.length]; for (int i = 0 ; i < typeArguments.length; i++) { hierarchies[i] = ClassUtils.resolveHierarchy(typeArguments[i]); } } + /** + * @return The type arguments + */ + public Class[] getTypeArguments() { + return typeArguments; + } + @Override public > Stream reduce(Class beanType, Stream candidates) { return candidates @@ -77,8 +89,7 @@ public > Stream reduce(Class beanType, Stream * @param classesToCompare An array of classes * @return Whether the types are compatible */ - protected int compare(List> classesToCompare) { - final Class[] typeArguments = getTypeArguments(); + private int compare(List> classesToCompare) { if (classesToCompare.isEmpty() && typeArguments.length == 0) { return 0; } else if (classesToCompare.size() != typeArguments.length) { @@ -100,6 +111,18 @@ protected int compare(List> classesToCompare) { } return comparison; } + } + private > List> getTypeArguments(Class beanType, BT candidate) { + if (candidate instanceof BeanDefinition) { + BeanDefinition definition = (BeanDefinition) candidate; + return definition.getTypeArguments(beanType).stream().map(Argument::getType).collect(Collectors.toList()); + } else { + if (beanType.isInterface()) { + return Arrays.asList(GenericTypeUtils.resolveInterfaceTypeArguments(candidate.getBeanType(), beanType)); + } else { + return Arrays.asList(GenericTypeUtils.resolveSuperTypeGenericArguments(candidate.getBeanType(), beanType)); + } + } } } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/ExactTypeArgumentNameQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/ExactTypeArgumentNameQualifier.java index f5e3138ebac..987a0915b62 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/ExactTypeArgumentNameQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/ExactTypeArgumentNameQualifier.java @@ -44,7 +44,7 @@ final class ExactTypeArgumentNameQualifier extends FilteringQualifier { } @Override - public boolean isQualifies(Class beanType, BeanType candidate) { + public boolean doesQualify(Class beanType, BeanType candidate) { if (!beanType.isAssignableFrom(candidate.getBeanType())) { return false; } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/FilteringCompositeQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/FilteringCompositeQualifier.java index 2d65196b2b8..d70e7a491a2 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/FilteringCompositeQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/FilteringCompositeQualifier.java @@ -42,9 +42,9 @@ final class FilteringCompositeQualifier extends FilteringQualifier { } @Override - public boolean isQualifies(Class beanType, BeanType candidate) { + public boolean doesQualify(Class beanType, BeanType candidate) { for (FilteringQualifier qualifier : qualifiers) { - if (!qualifier.isQualifies(beanType, candidate)) { + if (!qualifier.doesQualify(beanType, candidate)) { return false; } } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/FilteringQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/FilteringQualifier.java index f4fbdc42191..3a8bbd1de87 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/FilteringQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/FilteringQualifier.java @@ -36,13 +36,13 @@ public abstract class FilteringQualifier implements Qualifier { @Override public > Stream reduce(Class beanType, Stream candidates) { - return candidates.filter(candidate -> isQualifies(beanType, candidate)); + return candidates.filter(candidate -> doesQualify(beanType, candidate)); } @Override - public boolean isQualifies(Class beanType, Collection> candidates) { + public boolean doesQualify(Class beanType, Collection> candidates) { for (BeanType candidate : candidates) { - if (isQualifies(beanType, candidate)) { + if (doesQualify(beanType, candidate)) { return true; } } @@ -53,11 +53,11 @@ public boolean isQualifies(Class beanType, Collection> public > Collection filter(Class beanType, Collection candidates) { int size = candidates.size(); if (size == 1) { - return isQualifies(beanType, candidates.iterator().next()) ? candidates : Collections.emptyList(); + return doesQualify(beanType, candidates.iterator().next()) ? candidates : Collections.emptyList(); } Collection result = new ArrayList<>(size); for (BT candidate : candidates) { - if (isQualifies(beanType, candidate)) { + if (doesQualify(beanType, candidate)) { result.add(candidate); } } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/InterceptorBindingQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/InterceptorBindingQualifier.java index b98a1609dc0..88481508d97 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/InterceptorBindingQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/InterceptorBindingQualifier.java @@ -97,7 +97,7 @@ private static Map>> findSupportedAnnotations(Co } @Override - public boolean isQualifies(Class beanType, BeanType candidate) { + public boolean doesQualify(Class beanType, BeanType candidate) { if (supportedInterceptorTypes.contains(candidate.getBeanType())) { return true; } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/NameQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/NameQualifier.java index c42ebec5782..3ffe36f8d14 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/NameQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/NameQualifier.java @@ -52,7 +52,7 @@ class NameQualifier extends FilteringQualifier implements io.micronaut.cor } @Override - public boolean isQualifies(Class beanType, BeanType candidate) { + public boolean doesQualify(Class beanType, BeanType candidate) { if (!QualifierUtils.matchType(beanType, candidate)) { return false; } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/NamedAnnotationStereotypeQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/NamedAnnotationStereotypeQualifier.java index 7ac366f775c..6f84781dd77 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/NamedAnnotationStereotypeQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/NamedAnnotationStereotypeQualifier.java @@ -39,7 +39,7 @@ final class NamedAnnotationStereotypeQualifier extends FilteringQualifier } @Override - public boolean isQualifies(Class beanType, BeanType candidate) { + public boolean doesQualify(Class beanType, BeanType candidate) { return candidate.getAnnotationMetadata().hasStereotype(stereotype); } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/NoneQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/NoneQualifier.java index 311e97e44db..b3e1d068008 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/NoneQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/NoneQualifier.java @@ -35,7 +35,7 @@ private NoneQualifier() { } @Override - public boolean isQualifies(Class beanType, BeanType candidate) { + public boolean doesQualify(Class beanType, BeanType candidate) { if (candidate instanceof BeanDefinition beanDefinition) { return beanDefinition.getDeclaredQualifier() == null; } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/PrimaryQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/PrimaryQualifier.java index 6fbca01bbe0..408f07e56a0 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/PrimaryQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/PrimaryQualifier.java @@ -37,7 +37,7 @@ private PrimaryQualifier() { } @Override - public boolean isQualifies(Class beanType, BeanType candidate) { + public boolean doesQualify(Class beanType, BeanType candidate) { if (!QualifierUtils.matchType(beanType, candidate)) { return false; } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/RepeatableAnnotationQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/RepeatableAnnotationQualifier.java index 22b0ca6368c..89c41b0a2d9 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/RepeatableAnnotationQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/RepeatableAnnotationQualifier.java @@ -53,7 +53,7 @@ public String toString() { } @Override - public boolean isQualifies(Class beanType, BeanType candidate) { + public boolean doesQualify(Class beanType, BeanType candidate) { final AnnotationValue declared = candidate.getAnnotationMetadata().getAnnotation(repeatableName); if (declared != null) { final List> repeated = declared.getAnnotations(AnnotationMetadata.VALUE_MEMBER); diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/TypeAnnotationQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/TypeAnnotationQualifier.java index dffac216bda..f2a794c9dc2 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/TypeAnnotationQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/TypeAnnotationQualifier.java @@ -58,7 +58,7 @@ public class TypeAnnotationQualifier extends FilteringQualifier { } @Override - public boolean isQualifies(Class beanType, BeanType candidate) { + public boolean doesQualify(Class beanType, BeanType candidate) { return areTypesCompatible(candidate.getBeanType()); } diff --git a/inject/src/main/java/io/micronaut/inject/qualifiers/TypeArgumentQualifier.java b/inject/src/main/java/io/micronaut/inject/qualifiers/TypeArgumentQualifier.java index b778333bef2..809f9397cb8 100644 --- a/inject/src/main/java/io/micronaut/inject/qualifiers/TypeArgumentQualifier.java +++ b/inject/src/main/java/io/micronaut/inject/qualifiers/TypeArgumentQualifier.java @@ -37,7 +37,7 @@ * @since 1.0 */ @Internal -public class TypeArgumentQualifier extends FilteringQualifier { +public final class TypeArgumentQualifier extends FilteringQualifier { private static final Logger LOG = ClassUtils.getLogger(TypeArgumentQualifier.class); private final Class[] typeArguments; @@ -50,7 +50,7 @@ public class TypeArgumentQualifier extends FilteringQualifier { } @Override - public boolean isQualifies(Class beanType, BeanType candidate) { + public boolean doesQualify(Class beanType, BeanType candidate) { if (!beanType.isAssignableFrom(candidate.getBeanType())) { return false; } @@ -74,7 +74,7 @@ public Class[] getTypeArguments() { * @param classes An array of classes * @return Whether the types are compatible */ - protected boolean areTypesCompatible(List> classes) { + private boolean areTypesCompatible(List> classes) { final Class[] typeArguments = this.typeArguments; return areTypesCompatible(typeArguments, classes); } @@ -85,7 +85,7 @@ protected boolean areTypesCompatible(List> classes) { * @param The bean type subclass * @return The list of type arguments */ - protected > List> getTypeArguments(Class beanType, BT candidate) { + private > List> getTypeArguments(Class beanType, BT candidate) { if (candidate instanceof BeanDefinition) { BeanDefinition definition = (BeanDefinition) candidate; return definition.getTypeArguments(beanType).stream().map(Argument::getType).collect(Collectors.toList());