io.micronaut.inject.qualifiers.InterceptorBindingQualifier Maven / Gradle / Ivy
/*
* Copyright 2017-2021 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.AnnotationMetadata;
import io.micronaut.core.annotation.AnnotationUtil;
import io.micronaut.core.annotation.AnnotationValue;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.core.util.ObjectUtils;
import io.micronaut.inject.BeanType;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
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.
*
* @param The bean type
* @author graemerocher
* @since 2.4.0
*/
@Internal
public final class InterceptorBindingQualifier implements Qualifier {
public static final String META_BINDING_VALUES = "$bindingValues";
private static final String META_MEMBER_INTERCEPTOR_TYPE = "interceptorType";
private final Map>> supportedAnnotationNames;
private final Set> supportedInterceptorTypes;
InterceptorBindingQualifier(AnnotationMetadata annotationMetadata) {
final Collection> annotationValues;
AnnotationValue av = annotationMetadata.findAnnotation(AnnotationUtil.ANN_INTERCEPTOR_BINDING_QUALIFIER).orElse(null);
if (av == null) {
annotationValues = Collections.emptyList();
} else {
annotationValues = (Collection) av.getAnnotations(AnnotationMetadata.VALUE_MEMBER);
}
supportedAnnotationNames = findSupportedAnnotations(annotationValues);
Set> supportedInterceptorTypes = CollectionUtils.newHashSet(annotationValues.size());
for (AnnotationValue> annotationValue : annotationValues) {
annotationValue.classValue(META_MEMBER_INTERCEPTOR_TYPE).ifPresent(supportedInterceptorTypes::add);
}
this.supportedInterceptorTypes = supportedInterceptorTypes;
}
/**
* Interceptor binding qualifiers.
* @param bindingAnnotations The binding annotations
*/
InterceptorBindingQualifier(Collection> bindingAnnotations) {
if (CollectionUtils.isNotEmpty(bindingAnnotations)) {
supportedAnnotationNames = findSupportedAnnotations(bindingAnnotations);
} else {
this.supportedAnnotationNames = Collections.emptyMap();
}
this.supportedInterceptorTypes = Collections.emptySet();
}
private static Map>> findSupportedAnnotations(Collection> annotationValues) {
final Map>> supportedAnnotationNames = CollectionUtils.newHashMap(annotationValues.size());
for (AnnotationValue> annotationValue : annotationValues) {
final String name = annotationValue.stringValue().orElse(null);
if (name == null) {
continue;
}
final AnnotationValue> members = annotationValue.getAnnotation(META_BINDING_VALUES).orElse(null);
if (members != null) {
List> existing = supportedAnnotationNames
.computeIfAbsent(name, k -> new ArrayList<>(5));
existing.add(members);
} else {
supportedAnnotationNames.put(name, null);
}
}
return supportedAnnotationNames;
}
@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()) {
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;
}
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) {
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;
}
}
return matched;
}
});
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
InterceptorBindingQualifier> that = (InterceptorBindingQualifier>) o;
return supportedAnnotationNames.equals(that.supportedAnnotationNames) && supportedInterceptorTypes.equals(that.supportedInterceptorTypes);
}
@Override
public int hashCode() {
return ObjectUtils.hash(supportedAnnotationNames, supportedInterceptorTypes);
}
@Override
public String toString() {
if (CollectionUtils.isEmpty(supportedAnnotationNames) && CollectionUtils.isEmpty(supportedInterceptorTypes)) {
return "@InterceptorBinding(NONE)";
} else {
return supportedAnnotationNames.keySet().stream().map((name) -> "@InterceptorBinding(" + name + ")").collect(Collectors.joining(" ")) +
supportedInterceptorTypes.stream().map((name) -> "@InterceptorBinding(interceptorType = " + name + ")").collect(Collectors.joining(" "));
}
}
private static @NonNull Collection> resolveInterceptorAnnotationValues(
@NonNull AnnotationMetadata annotationMetadata,
@Nullable String kind) {
List> bindings = annotationMetadata.getAnnotationValuesByName(AnnotationUtil.ANN_INTERCEPTOR_BINDING);
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();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy