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

Initial set of MergedAnnotations commits #22586

Closed
wants to merge 19 commits into from
Closed
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
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ configure(allprojects) { project ->
}
testCompile("io.mockk:mockk:1.9.1")
testCompile("org.hamcrest:hamcrest-all:1.3")
testCompile("org.assertj:assertj-core:3.11.0")
testRuntime("org.apache.logging.log4j:log4j-core:${log4jVersion}")
testRuntime("org.apache.logging.log4j:log4j-slf4j-impl:${log4jVersion}")
testRuntime("org.apache.logging.log4j:log4j-jul:${log4jVersion}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,11 @@
import org.springframework.core.MethodParameter;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
Expand Down Expand Up @@ -304,7 +306,7 @@ public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final
else if (primaryConstructor != null) {
continue;
}
AnnotationAttributes ann = findAutowiredAnnotation(candidate);
MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
if (ann == null) {
Class<?> userClass = ClassUtils.getUserClass(beanClass);
if (userClass != beanClass) {
Expand Down Expand Up @@ -453,7 +455,7 @@ private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

ReflectionUtils.doWithLocalFields(targetClass, field -> {
AnnotationAttributes ann = findAutowiredAnnotation(field);
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
Expand All @@ -471,7 +473,7 @@ private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
Expand Down Expand Up @@ -500,13 +502,12 @@ private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
}

@Nullable
private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
if (ao.getAnnotations().length > 0) { // autowiring annotations have to be local
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
if (attributes != null) {
return attributes;
}
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
MergedAnnotations annotations = MergedAnnotations.from(ao, SearchStrategy.INHERITED_ANNOTATIONS);
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
MergedAnnotation<?> annotation = annotations.get(type);
if (annotation.isPresent()) {
return annotation;
}
}
return null;
Expand All @@ -520,6 +521,21 @@ private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
* @param ann the Autowired annotation
* @return whether the annotation indicates that a dependency is required
*/
protected boolean determineRequiredStatus(MergedAnnotation<?> ann) {
return determineRequiredStatus(
ann.asMap(mergedAnnotation -> new AnnotationAttributes()));
}

/**
* Determine if the annotated field or method requires its dependency.
* <p>A 'required' dependency means that autowiring should fail when no beans
* are found. Otherwise, the autowiring process will simply bypass the field
* or method when no beans are found.
* @param ann the Autowired annotation
* @return whether the annotation indicates that a dependency is required
* @deprecated since 5.2 in favor of {@link #determineRequiredStatus(MergedAnnotation)}
*/
@Deprecated
protected boolean determineRequiredStatus(AnnotationAttributes ann) {
return (!ann.containsKey(this.requiredParameterName) ||
this.requiredParameterValue == ann.getBoolean(this.requiredParameterName));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@
import org.springframework.beans.factory.config.NamedBeanHolder;
import org.springframework.core.OrderComparator;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
Expand Down Expand Up @@ -666,22 +668,33 @@ public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> an
@Nullable
public <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
throws NoSuchBeanDefinitionException {
return findMergedAnnotationOnBean(beanName, annotationType).synthesize(
MergedAnnotation::isPresent).orElse(null);
}

A ann = null;
private <A extends Annotation> MergedAnnotation<A> findMergedAnnotationOnBean(
String beanName, Class<A> annotationType) {
Class<?> beanType = getType(beanName);
if (beanType != null) {
ann = AnnotationUtils.findAnnotation(beanType, annotationType);
MergedAnnotation<A> annotation = MergedAnnotations.from(beanType,
SearchStrategy.EXHAUSTIVE).get(annotationType);
if (annotation.isPresent()) {
return annotation;
}
}
if (ann == null && containsBeanDefinition(beanName)) {
if (containsBeanDefinition(beanName)) {
BeanDefinition bd = getMergedBeanDefinition(beanName);
if (bd instanceof AbstractBeanDefinition) {
AbstractBeanDefinition abd = (AbstractBeanDefinition) bd;
if (abd.hasBeanClass()) {
ann = AnnotationUtils.findAnnotation(abd.getBeanClass(), annotationType);
Class<?> beanClass = abd.getBeanClass();
if (beanClass != beanType) {
return MergedAnnotations.from(beanClass, SearchStrategy.EXHAUSTIVE).get(annotationType);
}
}
}
}
return ann;
return MergedAnnotation.missing();
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
import org.springframework.core.MethodParameter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.jndi.support.SimpleJndiBeanFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
Expand Down Expand Up @@ -379,19 +380,20 @@ private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
MergedAnnotations annotations = MergedAnnotations.from(field);
if (webServiceRefClass != null && annotations.isDirectlyPresent(webServiceRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
}
currElements.add(new WebServiceRefElement(field, field, null));
}
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
else if (ejbRefClass != null && annotations.isDirectlyPresent(ejbRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
currElements.add(new EjbRefElement(field, field, null));
}
else if (field.isAnnotationPresent(Resource.class)) {
else if (annotations.isDirectlyPresent(Resource.class)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
Expand All @@ -407,7 +409,8 @@ else if (field.isAnnotationPresent(Resource.class)) {
return;
}
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
MergedAnnotations annotations = MergedAnnotations.from(bridgedMethod);
if (webServiceRefClass != null && annotations.isDirectlyPresent(webServiceRefClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
}
Expand All @@ -417,7 +420,7 @@ else if (field.isAnnotationPresent(Resource.class)) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
}
else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
else if (ejbRefClass != null && annotations.isDirectlyPresent(ejbRefClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static methods");
}
Expand All @@ -427,7 +430,7 @@ else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass))
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
}
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
else if (annotations.isDirectlyPresent(Resource.class)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ class ConfigurationClassParser {

private final DeferredImportSelectorHandler deferredImportSelectorHandler = new DeferredImportSelectorHandler();

private final SourceClass objectSourceClass = new SourceClass(Object.class);


/**
* Create a new {@link ConfigurationClassParser} instance that will be used
Expand Down Expand Up @@ -639,8 +641,8 @@ private SourceClass asSourceClass(ConfigurationClass configurationClass) throws
* Factory method to obtain a {@link SourceClass} from a {@link Class}.
*/
SourceClass asSourceClass(@Nullable Class<?> classType) throws IOException {
if (classType == null) {
return new SourceClass(Object.class);
if (classType == null || classType.getName().startsWith("java.lang.annotation")) {
return this.objectSourceClass;
}
try {
// Sanity test that we can reflectively read annotations,
Expand Down Expand Up @@ -671,19 +673,22 @@ private Collection<SourceClass> asSourceClasses(String... classNames) throws IOE
* Factory method to obtain a {@link SourceClass} from a class name.
*/
SourceClass asSourceClass(@Nullable String className) throws IOException {
if (className == null) {
return new SourceClass(Object.class);
if (className == null || className.startsWith("java.lang.annotation")) {
return this.objectSourceClass;
}
if (className.startsWith("java")) {
// Never use ASM for core java types
try {
return new SourceClass(ClassUtils.forName(className, this.resourceLoader.getClassLoader()));
return new SourceClass(ClassUtils.forName(className,
this.resourceLoader.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to load class [" + className + "]", ex);
throw new NestedIOException(
"Failed to load class [" + className + "]", ex);
}
}
return new SourceClass(this.metadataReaderFactory.getMetadataReader(className));
return new SourceClass(
this.metadataReaderFactory.getMetadataReader(className));
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.MethodFilter;

/**
* Helper for resolving synthetic {@link Method#isBridge bridge Methods} to the
Expand All @@ -47,6 +50,8 @@
*/
public final class BridgeMethodResolver {

private static final Map<Method, Method> cache = new ConcurrentReferenceHashMap<>();

private BridgeMethodResolver() {
}

Expand All @@ -64,32 +69,26 @@ public static Method findBridgedMethod(Method bridgeMethod) {
if (!bridgeMethod.isBridge()) {
return bridgeMethod;
}

// Gather all methods with matching name and parameter size.
List<Method> candidateMethods = new ArrayList<>();
Method[] methods = ReflectionUtils.getAllDeclaredMethods(bridgeMethod.getDeclaringClass());
for (Method candidateMethod : methods) {
if (isBridgedCandidateFor(candidateMethod, bridgeMethod)) {
candidateMethods.add(candidateMethod);
Method bridgedMethod = cache.get(bridgeMethod);
if (bridgedMethod == null) {
// Gather all methods with matching name and parameter size.
List<Method> candidateMethods = new ArrayList<>();
MethodFilter filter = candidateMethod ->
isBridgedCandidateFor(candidateMethod, bridgeMethod);
ReflectionUtils.doWithMethods(bridgeMethod.getDeclaringClass(), candidateMethods::add, filter);
if (!candidateMethods.isEmpty()) {
bridgedMethod = candidateMethods.size() == 1 ?
candidateMethods.get(0) :
searchCandidates(candidateMethods, bridgeMethod);
}
if (bridgedMethod == null) {
// A bridge method was passed in but we couldn't find the bridged method.
// Let's proceed with the passed-in method and hope for the best...
bridgedMethod = bridgeMethod;
}
cache.put(bridgeMethod, bridgedMethod);
}

// Now perform simple quick check.
if (candidateMethods.size() == 1) {
return candidateMethods.get(0);
}

// Search for candidate match.
Method bridgedMethod = searchCandidates(candidateMethods, bridgeMethod);
if (bridgedMethod != null) {
// Bridged method found...
return bridgedMethod;
}
else {
// A bridge method was passed in but we couldn't find the bridged method.
// Let's proceed with the passed-in method and hope for the best...
return bridgeMethod;
}
return bridgedMethod;
}

/**
Expand Down
Loading