Consistent use of AnnotatedElementUtils.findMergedAnnotation/hasAnnotation
Issue: SPR-13440
This commit is contained in:
@@ -19,7 +19,7 @@ package org.springframework.scheduling.aspectj;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
/**
|
||||
@@ -68,9 +68,9 @@ public aspect AnnotationAsyncExecutionAspect extends AbstractAsyncExecutionAspec
|
||||
protected String getExecutorQualifier(Method method) {
|
||||
// Maintainer's note: changes made here should also be made in
|
||||
// AnnotationAsyncExecutionInterceptor#getExecutorQualifier
|
||||
Async async = AnnotationUtils.findAnnotation(method, Async.class);
|
||||
Async async = AnnotatedElementUtils.findMergedAnnotation(method, Async.class);
|
||||
if (async == null) {
|
||||
async = AnnotationUtils.findAnnotation(method.getDeclaringClass(), Async.class);
|
||||
async = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Async.class);
|
||||
}
|
||||
return (async != null ? async.value() : null);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,22 +18,19 @@ package org.springframework.context.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
|
||||
/**
|
||||
* Utilities for processing {@link Bean}-annotated methods.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
class BeanAnnotationHelper {
|
||||
|
||||
/**
|
||||
* Return whether the given method is directly or indirectly annotated with
|
||||
* the {@link Bean} annotation.
|
||||
*/
|
||||
public static boolean isBeanAnnotated(Method method) {
|
||||
return (AnnotationUtils.findAnnotation(method, Bean.class) != null);
|
||||
return AnnotatedElementUtils.hasAnnotation(method, Bean.class);
|
||||
}
|
||||
|
||||
public static String determineBeanNameFor(Method beanMethod) {
|
||||
@@ -41,7 +38,7 @@ class BeanAnnotationHelper {
|
||||
String beanName = beanMethod.getName();
|
||||
|
||||
// Check to see if the user has explicitly set a custom bean name...
|
||||
Bean bean = AnnotationUtils.findAnnotation(beanMethod, Bean.class);
|
||||
Bean bean = AnnotatedElementUtils.findMergedAnnotation(beanMethod, Bean.class);
|
||||
if (bean != null && bean.name().length > 0) {
|
||||
beanName = bean.name()[0];
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.cglib.proxy.NoOp;
|
||||
import org.springframework.cglib.transform.ClassEmitterTransformer;
|
||||
import org.springframework.cglib.transform.TransformingClassGenerator;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.objenesis.ObjenesisException;
|
||||
import org.springframework.objenesis.SpringObjenesis;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -311,7 +311,7 @@ class ConfigurationClassEnhancer {
|
||||
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
|
||||
|
||||
// Determine whether this bean is a scoped-proxy
|
||||
Scope scope = AnnotationUtils.findAnnotation(beanMethod, Scope.class);
|
||||
Scope scope = AnnotatedElementUtils.findMergedAnnotation(beanMethod, Scope.class);
|
||||
if (scope != null && scope.proxyMode() != ScopedProxyMode.NO) {
|
||||
String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
|
||||
if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,7 +35,6 @@ import org.springframework.context.expression.AnnotatedElementKey;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -214,7 +213,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
|
||||
}
|
||||
|
||||
protected <A extends Annotation> A getMethodAnnotation(Class<A> annotationType) {
|
||||
return AnnotationUtils.findAnnotation(this.method, annotationType);
|
||||
return AnnotatedElementUtils.findMergedAnnotation(this.method, annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,8 +39,8 @@ import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.MethodIntrospector;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -129,7 +129,7 @@ public class EventListenerMethodProcessor implements SmartInitializingSingleton,
|
||||
new MethodIntrospector.MetadataLookup<EventListener>() {
|
||||
@Override
|
||||
public EventListener inspect(Method method) {
|
||||
return AnnotationUtils.findAnnotation(method, EventListener.class);
|
||||
return AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class);
|
||||
}
|
||||
});
|
||||
if (annotatedMethods.isEmpty()) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.concurrent.Executor;
|
||||
|
||||
import org.springframework.aop.interceptor.AsyncExecutionInterceptor;
|
||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
|
||||
/**
|
||||
* Specialization of {@link AsyncExecutionInterceptor} that delegates method execution to
|
||||
@@ -78,9 +78,9 @@ public class AnnotationAsyncExecutionInterceptor extends AsyncExecutionIntercept
|
||||
protected String getExecutorQualifier(Method method) {
|
||||
// Maintainer's note: changes made here should also be made in
|
||||
// AnnotationAsyncExecutionAspect#getExecutorQualifier
|
||||
Async async = AnnotationUtils.findAnnotation(method, Async.class);
|
||||
Async async = AnnotatedElementUtils.findMergedAnnotation(method, Async.class);
|
||||
if (async == null) {
|
||||
async = AnnotationUtils.findAnnotation(method.getDeclaringClass(), Async.class);
|
||||
async = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Async.class);
|
||||
}
|
||||
return (async != null ? async.value() : null);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ import org.springframework.context.event.test.GenericEventPojo;
|
||||
import org.springframework.context.event.test.Identifiable;
|
||||
import org.springframework.context.event.test.TestEvent;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
@@ -868,6 +869,16 @@ public class AnnotationDrivenEventListenerTests {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@EventListener
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ConditionalEvent {
|
||||
|
||||
@AliasFor(annotation = EventListener.class, attribute = "condition")
|
||||
String value();
|
||||
}
|
||||
|
||||
|
||||
@Component
|
||||
static class ConditionalEventListener extends TestEventListener {
|
||||
|
||||
@@ -883,12 +894,12 @@ public class AnnotationDrivenEventListenerTests {
|
||||
super.handleString(payload);
|
||||
}
|
||||
|
||||
@EventListener(condition = "#root.event.timestamp > #p0")
|
||||
@ConditionalEvent("#root.event.timestamp > #p0")
|
||||
public void handleTimestamp(Long timestamp) {
|
||||
collectEvent(timestamp);
|
||||
}
|
||||
|
||||
@EventListener(condition = "@conditionEvaluator.valid(#p0)")
|
||||
@ConditionalEvent("@conditionEvaluator.valid(#p0)")
|
||||
public void handleRatio(Double ratio) {
|
||||
collectEvent(ratio);
|
||||
}
|
||||
|
||||
@@ -271,10 +271,15 @@ public class AnnotatedElementUtils {
|
||||
Assert.notNull(element, "AnnotatedElement must not be null");
|
||||
Assert.notNull(annotationType, "annotationType must not be null");
|
||||
|
||||
// Shortcut: directly present on the element, with no processing needed?
|
||||
if (element.isAnnotationPresent(annotationType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Boolean.TRUE.equals(searchWithGetSemantics(element, annotationType, null, new SimpleAnnotationProcessor<Boolean>() {
|
||||
@Override
|
||||
public Boolean process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
|
||||
boolean found = annotation.annotationType() == annotationType;
|
||||
boolean found = (annotation.annotationType() == annotationType);
|
||||
return (found ? Boolean.TRUE : CONTINUE);
|
||||
}
|
||||
}));
|
||||
@@ -324,6 +329,15 @@ public class AnnotatedElementUtils {
|
||||
* @see AnnotationUtils#synthesizeAnnotation(Map, Class, AnnotatedElement)
|
||||
*/
|
||||
public static <A extends Annotation> A getMergedAnnotation(AnnotatedElement element, Class<A> annotationType) {
|
||||
Assert.notNull(annotationType, "annotationType must not be null");
|
||||
|
||||
// Shortcut: directly present on the element, with no merging needed?
|
||||
A annotation = element.getAnnotation(annotationType);
|
||||
if (annotation != null) {
|
||||
return AnnotationUtils.synthesizeAnnotation(annotation, element);
|
||||
}
|
||||
|
||||
// Exhaustive retrieval of merged annotation attributes...
|
||||
AnnotationAttributes attributes = getMergedAnnotationAttributes(element, annotationType);
|
||||
return AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element);
|
||||
}
|
||||
@@ -412,6 +426,38 @@ public class AnnotatedElementUtils {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an annotation of the specified {@code annotationType}
|
||||
* is <em>available</em> on the supplied {@link AnnotatedElement} or
|
||||
* within the annotation hierarchy <em>above</em> the specified element.
|
||||
* <p>If this method returns {@code true}, then {@link #findMergedAnnotationAttributes}
|
||||
* will return a non-null value.
|
||||
* <p>This method follows <em>find semantics</em> as described in the
|
||||
* {@linkplain AnnotatedElementUtils class-level javadoc}.
|
||||
* @param element the annotated element
|
||||
* @param annotationType the annotation type to find
|
||||
* @return {@code true} if a matching annotation is present
|
||||
* @since 4.3
|
||||
*/
|
||||
public static boolean hasAnnotation(AnnotatedElement element, final Class<? extends Annotation> annotationType) {
|
||||
Assert.notNull(element, "AnnotatedElement must not be null");
|
||||
Assert.notNull(annotationType, "annotationType must not be null");
|
||||
|
||||
// Shortcut: directly present on the element, with no processing needed?
|
||||
if (element.isAnnotationPresent(annotationType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Boolean.TRUE.equals(searchWithFindSemantics(element, annotationType, annotationType.getName(),
|
||||
new SimpleAnnotationProcessor<Boolean>() {
|
||||
@Override
|
||||
public Boolean process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
|
||||
boolean found = (annotation.annotationType() == annotationType);
|
||||
return (found ? Boolean.TRUE : CONTINUE);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first annotation of the specified {@code annotationType} within
|
||||
* the annotation hierarchy <em>above</em> the supplied {@code element},
|
||||
@@ -430,6 +476,14 @@ public class AnnotatedElementUtils {
|
||||
*/
|
||||
public static <A extends Annotation> A findMergedAnnotation(AnnotatedElement element, Class<A> annotationType) {
|
||||
Assert.notNull(annotationType, "annotationType must not be null");
|
||||
|
||||
// Shortcut: directly present on the element, with no merging needed?
|
||||
A annotation = element.getDeclaredAnnotation(annotationType);
|
||||
if (annotation != null) {
|
||||
return AnnotationUtils.synthesizeAnnotation(annotation, element);
|
||||
}
|
||||
|
||||
// Exhaustive retrieval of merged annotation attributes...
|
||||
AnnotationAttributes attributes = findMergedAnnotationAttributes(element, annotationType, false, false);
|
||||
return AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element);
|
||||
}
|
||||
@@ -483,9 +537,8 @@ public class AnnotatedElementUtils {
|
||||
Assert.notNull(element, "AnnotatedElement must not be null");
|
||||
Assert.notNull(annotationType, "annotationType must not be null");
|
||||
|
||||
MergedAnnotationAttributesProcessor processor = new MergedAnnotationAttributesProcessor(annotationType, null,
|
||||
false, false, true);
|
||||
|
||||
MergedAnnotationAttributesProcessor processor =
|
||||
new MergedAnnotationAttributesProcessor(annotationType, null, false, false, true);
|
||||
searchWithFindSemantics(element, annotationType, annotationType.getName(), processor);
|
||||
|
||||
Set<A> annotations = new LinkedHashSet<A>();
|
||||
@@ -831,8 +884,7 @@ public class AnnotatedElementUtils {
|
||||
try {
|
||||
// Locally declared annotations (ignoring @Inherited)
|
||||
Annotation[] annotations = element.getDeclaredAnnotations();
|
||||
|
||||
List<T> aggregatedResults = processor.aggregates() ? new ArrayList<T>() : null;
|
||||
List<T> aggregatedResults = (processor.aggregates() ? new ArrayList<T>() : null);
|
||||
|
||||
// Search in local annotations
|
||||
for (Annotation annotation : annotations) {
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.EmbeddedValueResolver;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.jms.listener.MessageListenerContainer;
|
||||
import org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter;
|
||||
import org.springframework.jms.support.converter.MessageConverter;
|
||||
@@ -187,13 +187,11 @@ public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint imple
|
||||
}
|
||||
|
||||
private SendTo getSendTo(Method specificMethod) {
|
||||
SendTo ann = AnnotationUtils.getAnnotation(specificMethod, SendTo.class);
|
||||
if (ann != null) {
|
||||
return ann;
|
||||
}
|
||||
else {
|
||||
return AnnotationUtils.getAnnotation(specificMethod.getDeclaringClass(), SendTo.class);
|
||||
SendTo ann = AnnotatedElementUtils.findMergedAnnotation(specificMethod, SendTo.class);
|
||||
if (ann == null) {
|
||||
ann = AnnotatedElementUtils.findMergedAnnotation(specificMethod.getDeclaringClass(), SendTo.class);
|
||||
}
|
||||
return ann;
|
||||
}
|
||||
|
||||
private String resolve(String value) {
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.SynthesizingMethodParameter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -33,10 +33,11 @@ import org.springframework.util.ClassUtils;
|
||||
/**
|
||||
* Encapsulates information about a handler method consisting of a
|
||||
* {@linkplain #getMethod() method} and a {@linkplain #getBean() bean}.
|
||||
* Provides convenient access to method parameters, method return value, method annotations.
|
||||
* Provides convenient access to method parameters, the method return value,
|
||||
* method annotations, etc.
|
||||
*
|
||||
* <p>The class may be created with a bean instance or with a bean name (e.g. lazy-init bean,
|
||||
* prototype bean). Use {@link #createWithResolvedBean()} to obtain a {@link HandlerMethod}
|
||||
* prototype bean). Use {@link #createWithResolvedBean()} to obtain a {@code HandlerMethod}
|
||||
* instance with a bean instance resolved through the associated {@link BeanFactory}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
@@ -61,6 +62,8 @@ public class HandlerMethod {
|
||||
|
||||
private final MethodParameter[] parameters;
|
||||
|
||||
private final HandlerMethod resolvedFromHandlerMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Create an instance from a bean instance and a method.
|
||||
@@ -74,6 +77,7 @@ public class HandlerMethod {
|
||||
this.method = method;
|
||||
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
this.parameters = initMethodParameters();
|
||||
this.resolvedFromHandlerMethod = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,12 +93,13 @@ public class HandlerMethod {
|
||||
this.method = bean.getClass().getMethod(methodName, parameterTypes);
|
||||
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(this.method);
|
||||
this.parameters = initMethodParameters();
|
||||
this.resolvedFromHandlerMethod = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance from a bean name, a method, and a {@code BeanFactory}.
|
||||
* The method {@link #createWithResolvedBean()} may be used later to
|
||||
* re-create the {@code HandlerMethod} with an initialized the bean.
|
||||
* re-create the {@code HandlerMethod} with an initialized bean.
|
||||
*/
|
||||
public HandlerMethod(String beanName, BeanFactory beanFactory, Method method) {
|
||||
Assert.hasText(beanName, "Bean name is required");
|
||||
@@ -106,6 +111,7 @@ public class HandlerMethod {
|
||||
this.method = method;
|
||||
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
this.parameters = initMethodParameters();
|
||||
this.resolvedFromHandlerMethod = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,6 +125,7 @@ public class HandlerMethod {
|
||||
this.method = handlerMethod.method;
|
||||
this.bridgedMethod = handlerMethod.bridgedMethod;
|
||||
this.parameters = handlerMethod.parameters;
|
||||
this.resolvedFromHandlerMethod = handlerMethod.resolvedFromHandlerMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,6 +140,7 @@ public class HandlerMethod {
|
||||
this.method = handlerMethod.method;
|
||||
this.bridgedMethod = handlerMethod.bridgedMethod;
|
||||
this.parameters = handlerMethod.parameters;
|
||||
this.resolvedFromHandlerMethod = handlerMethod;
|
||||
}
|
||||
|
||||
|
||||
@@ -183,6 +191,15 @@ public class HandlerMethod {
|
||||
return this.parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HandlerMethod from which this HandlerMethod instance was
|
||||
* resolved via {@link #createWithResolvedBean()}.
|
||||
* @since 4.3
|
||||
*/
|
||||
public HandlerMethod getResolvedFromHandlerMethod() {
|
||||
return this.resolvedFromHandlerMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HandlerMethod return type.
|
||||
*/
|
||||
@@ -207,11 +224,24 @@ public class HandlerMethod {
|
||||
/**
|
||||
* Returns a single annotation on the underlying method traversing its super methods
|
||||
* if no annotation can be found on the given method itself.
|
||||
* @param annotationType the type of annotation to introspect the method for.
|
||||
* <p>Also supports <em>merged</em> composed annotations with attribute
|
||||
* overrides as of Spring Framework 4.3.
|
||||
* @param annotationType the type of annotation to introspect the method for
|
||||
* @return the annotation, or {@code null} if none found
|
||||
* @see AnnotatedElementUtils#findMergedAnnotation
|
||||
*/
|
||||
public <A extends Annotation> A getMethodAnnotation(Class<A> annotationType) {
|
||||
return AnnotationUtils.findAnnotation(this.method, annotationType);
|
||||
return AnnotatedElementUtils.findMergedAnnotation(this.method, annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the parameter is declared with the given annotation type.
|
||||
* @param annotationType the annotation type to look for
|
||||
* @since 4.3
|
||||
* @see AnnotatedElementUtils#hasAnnotation
|
||||
*/
|
||||
public <A extends Annotation> boolean hasMethodAnnotation(Class<A> annotationType) {
|
||||
return AnnotatedElementUtils.hasAnnotation(this.method, annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,6 +257,9 @@ public class HandlerMethod {
|
||||
return new HandlerMethod(this, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a short representation of this handler method for log message purposes.
|
||||
*/
|
||||
public String getShortLogMessage() {
|
||||
int args = this.method.getParameterTypes().length;
|
||||
return getBeanType().getName() + "#" + this.method.getName() + "[" + args + " args]";
|
||||
@@ -279,6 +312,11 @@ public class HandlerMethod {
|
||||
return HandlerMethod.this.getMethodAnnotation(annotationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Annotation> boolean hasMethodAnnotation(Class<T> annotationType) {
|
||||
return HandlerMethod.this.hasMethodAnnotation(annotationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerMethodParameter clone() {
|
||||
return new HandlerMethodParameter(this);
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.security.Principal;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
@@ -132,13 +133,13 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
|
||||
|
||||
@Override
|
||||
public boolean supportsReturnType(MethodParameter returnType) {
|
||||
if (returnType.getMethodAnnotation(SendTo.class) != null ||
|
||||
AnnotationUtils.getAnnotation(returnType.getDeclaringClass(), SendTo.class) != null ||
|
||||
returnType.getMethodAnnotation(SendToUser.class) != null ||
|
||||
AnnotationUtils.getAnnotation(returnType.getDeclaringClass(), SendToUser.class) != null) {
|
||||
if (returnType.hasMethodAnnotation(SendTo.class) ||
|
||||
AnnotatedElementUtils.hasAnnotation(returnType.getDeclaringClass(), SendTo.class) ||
|
||||
returnType.hasMethodAnnotation(SendToUser.class) ||
|
||||
AnnotatedElementUtils.hasAnnotation(returnType.getDeclaringClass(), SendToUser.class)) {
|
||||
return true;
|
||||
}
|
||||
return (!this.annotationRequired);
|
||||
return !this.annotationRequired;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -186,24 +187,24 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
|
||||
}
|
||||
|
||||
private SendToUser getSendToUser(MethodParameter returnType) {
|
||||
SendToUser annot = returnType.getMethodAnnotation(SendToUser.class);
|
||||
if (annot != null && !ObjectUtils.isEmpty((annot.value()))) {
|
||||
SendToUser annot = AnnotatedElementUtils.findMergedAnnotation(returnType.getMethod(), SendToUser.class);
|
||||
if (annot != null && !ObjectUtils.isEmpty(annot.value())) {
|
||||
return annot;
|
||||
}
|
||||
SendToUser typeAnnot = AnnotationUtils.getAnnotation(returnType.getDeclaringClass(), SendToUser.class);
|
||||
if (typeAnnot != null && !ObjectUtils.isEmpty((typeAnnot.value()))) {
|
||||
SendToUser typeAnnot = AnnotatedElementUtils.findMergedAnnotation(returnType.getDeclaringClass(), SendToUser.class);
|
||||
if (typeAnnot != null && !ObjectUtils.isEmpty(typeAnnot.value())) {
|
||||
return typeAnnot;
|
||||
}
|
||||
return (annot != null ? annot : typeAnnot);
|
||||
}
|
||||
|
||||
private SendTo getSendTo(MethodParameter returnType) {
|
||||
SendTo sendTo = returnType.getMethodAnnotation(SendTo.class);
|
||||
if (sendTo != null && !ObjectUtils.isEmpty((sendTo.value()))) {
|
||||
SendTo sendTo = AnnotatedElementUtils.findMergedAnnotation(returnType.getMethod(), SendTo.class);
|
||||
if (sendTo != null && !ObjectUtils.isEmpty(sendTo.value())) {
|
||||
return sendTo;
|
||||
}
|
||||
else {
|
||||
return AnnotationUtils.getAnnotation(returnType.getDeclaringClass(), SendTo.class);
|
||||
return AnnotatedElementUtils.findMergedAnnotation(returnType.getDeclaringClass(), SendTo.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
import org.springframework.messaging.Message;
|
||||
@@ -360,14 +360,14 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
|
||||
@Override
|
||||
protected boolean isHandler(Class<?> beanType) {
|
||||
return (AnnotationUtils.findAnnotation(beanType, Controller.class) != null);
|
||||
return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SimpMessageMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
|
||||
MessageMapping messageAnn = AnnotationUtils.findAnnotation(method, MessageMapping.class);
|
||||
MessageMapping messageAnn = AnnotatedElementUtils.findMergedAnnotation(method, MessageMapping.class);
|
||||
if (messageAnn != null) {
|
||||
MessageMapping typeAnn = AnnotationUtils.findAnnotation(handlerType, MessageMapping.class);
|
||||
MessageMapping typeAnn = AnnotatedElementUtils.findMergedAnnotation(handlerType, MessageMapping.class);
|
||||
// Only actually register it if there are destinations specified;
|
||||
// otherwise @MessageMapping is just being used as a (meta-annotation) marker.
|
||||
if (messageAnn.value().length > 0 || (typeAnn != null && typeAnn.value().length > 0)) {
|
||||
@@ -379,9 +379,9 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
}
|
||||
}
|
||||
|
||||
SubscribeMapping subscribeAnn = AnnotationUtils.findAnnotation(method, SubscribeMapping.class);
|
||||
SubscribeMapping subscribeAnn = AnnotatedElementUtils.findMergedAnnotation(method, SubscribeMapping.class);
|
||||
if (subscribeAnn != null) {
|
||||
MessageMapping typeAnn = AnnotationUtils.findAnnotation(handlerType, MessageMapping.class);
|
||||
MessageMapping typeAnn = AnnotatedElementUtils.findMergedAnnotation(handlerType, MessageMapping.class);
|
||||
// Only actually register it if there are destinations specified;
|
||||
// otherwise @SubscribeMapping is just being used as a (meta-annotation) marker.
|
||||
if (subscribeAnn.value().length > 0 || (typeAnn != null && typeAnn.value().length > 0)) {
|
||||
|
||||
@@ -95,9 +95,9 @@ public class SubscriptionMethodReturnValueHandler implements HandlerMethodReturn
|
||||
|
||||
@Override
|
||||
public boolean supportsReturnType(MethodParameter returnType) {
|
||||
return (returnType.getMethodAnnotation(SubscribeMapping.class) != null &&
|
||||
returnType.getMethodAnnotation(SendTo.class) == null &&
|
||||
returnType.getMethodAnnotation(SendToUser.class) == null);
|
||||
return (returnType.hasMethodAnnotation(SubscribeMapping.class) &&
|
||||
!returnType.hasMethodAnnotation(SendTo.class) &&
|
||||
!returnType.hasMethodAnnotation(SendToUser.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.messaging.simp.annotation.support;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -34,6 +36,7 @@ import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.core.annotation.SynthesizingMethodParameter;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
@@ -52,7 +55,7 @@ import org.springframework.util.MimeType;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.BDDMockito.*;
|
||||
import static org.springframework.messaging.handler.DestinationPatternsMessageCondition.LOOKUP_DESTINATION_HEADER;
|
||||
import static org.springframework.messaging.handler.DestinationPatternsMessageCondition.*;
|
||||
import static org.springframework.messaging.handler.annotation.support.DestinationVariableMethodArgumentResolver.*;
|
||||
import static org.springframework.messaging.support.MessageHeaderAccessor.*;
|
||||
|
||||
@@ -110,31 +113,31 @@ public class SendToMethodReturnValueHandlerTests {
|
||||
jsonMessagingTemplate.setMessageConverter(new MappingJackson2MessageConverter());
|
||||
this.jsonHandler = new SendToMethodReturnValueHandler(jsonMessagingTemplate, true);
|
||||
|
||||
Method method = this.getClass().getDeclaredMethod("handleNoAnnotations");
|
||||
Method method = getClass().getDeclaredMethod("handleNoAnnotations");
|
||||
this.noAnnotationsReturnType = new SynthesizingMethodParameter(method, -1);
|
||||
|
||||
method = this.getClass().getDeclaredMethod("handleAndSendToDefaultDestination");
|
||||
method = getClass().getDeclaredMethod("handleAndSendToDefaultDestination");
|
||||
this.sendToDefaultDestReturnType = new SynthesizingMethodParameter(method, -1);
|
||||
|
||||
method = this.getClass().getDeclaredMethod("handleAndSendTo");
|
||||
method = getClass().getDeclaredMethod("handleAndSendTo");
|
||||
this.sendToReturnType = new SynthesizingMethodParameter(method, -1);
|
||||
|
||||
method = this.getClass().getDeclaredMethod("handleAndSendToWithPlaceholders");
|
||||
method = getClass().getDeclaredMethod("handleAndSendToWithPlaceholders");
|
||||
this.sendToWithPlaceholdersReturnType = new SynthesizingMethodParameter(method, -1);
|
||||
|
||||
method = this.getClass().getDeclaredMethod("handleAndSendToUser");
|
||||
method = getClass().getDeclaredMethod("handleAndSendToUser");
|
||||
this.sendToUserReturnType = new SynthesizingMethodParameter(method, -1);
|
||||
|
||||
method = this.getClass().getDeclaredMethod("handleAndSendToUserSingleSession");
|
||||
method = getClass().getDeclaredMethod("handleAndSendToUserSingleSession");
|
||||
this.sendToUserSingleSessionReturnType = new SynthesizingMethodParameter(method, -1);
|
||||
|
||||
method = this.getClass().getDeclaredMethod("handleAndSendToUserDefaultDestination");
|
||||
method = getClass().getDeclaredMethod("handleAndSendToUserDefaultDestination");
|
||||
this.sendToUserDefaultDestReturnType = new SynthesizingMethodParameter(method, -1);
|
||||
|
||||
method = this.getClass().getDeclaredMethod("handleAndSendToUserDefaultDestinationSingleSession");
|
||||
method = getClass().getDeclaredMethod("handleAndSendToUserDefaultDestinationSingleSession");
|
||||
this.sendToUserSingleSessionDefaultDestReturnType = new SynthesizingMethodParameter(method, -1);
|
||||
|
||||
method = this.getClass().getDeclaredMethod("handleAndSendToJsonView");
|
||||
method = getClass().getDeclaredMethod("handleAndSendToJsonView");
|
||||
this.jsonViewReturnType = new SynthesizingMethodParameter(method, -1);
|
||||
|
||||
method = SendToTestBean.class.getDeclaredMethod("handleNoAnnotation");
|
||||
@@ -287,6 +290,7 @@ public class SendToMethodReturnValueHandlerTests {
|
||||
|
||||
private void assertResponse(MethodParameter methodParameter, String sessionId,
|
||||
int index, String destination) {
|
||||
|
||||
SimpMessageHeaderAccessor accessor = getCapturedAccessor(index);
|
||||
assertEquals(sessionId, accessor.getSessionId());
|
||||
assertEquals(destination, accessor.getDestination());
|
||||
@@ -546,6 +550,23 @@ public class SendToMethodReturnValueHandlerTests {
|
||||
}
|
||||
}
|
||||
|
||||
@SendTo
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MySendTo {
|
||||
|
||||
@AliasFor(annotation = SendTo.class, attribute = "value")
|
||||
String[] dest();
|
||||
}
|
||||
|
||||
@SendToUser
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MySendToUser {
|
||||
|
||||
@AliasFor(annotation = SendToUser.class, attribute = "destinations")
|
||||
String[] dest();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public String handleNoAnnotations() {
|
||||
return PAYLOAD;
|
||||
@@ -586,7 +607,6 @@ public class SendToMethodReturnValueHandlerTests {
|
||||
return PAYLOAD;
|
||||
}
|
||||
|
||||
@SendTo("/dest")
|
||||
@JsonView(MyJacksonView1.class) @SuppressWarnings("unused")
|
||||
public JacksonViewBean handleAndSendToJsonView() {
|
||||
JacksonViewBean payload = new JacksonViewBean();
|
||||
@@ -596,7 +616,8 @@ public class SendToMethodReturnValueHandlerTests {
|
||||
return payload;
|
||||
}
|
||||
|
||||
@SendTo("/dest-default") @SuppressWarnings("unused")
|
||||
|
||||
@MySendTo(dest = "/dest-default") @SuppressWarnings("unused")
|
||||
private static class SendToTestBean {
|
||||
|
||||
public String handleNoAnnotation() {
|
||||
@@ -608,14 +629,13 @@ public class SendToMethodReturnValueHandlerTests {
|
||||
return PAYLOAD;
|
||||
}
|
||||
|
||||
@SendTo({"/dest3", "/dest4"})
|
||||
@MySendTo(dest = {"/dest3", "/dest4"})
|
||||
public String handleAndSendToOverride() {
|
||||
return PAYLOAD;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SendToUser("/dest-default") @SuppressWarnings("unused")
|
||||
@MySendToUser(dest = "/dest-default") @SuppressWarnings("unused")
|
||||
private static class SendToUserTestBean {
|
||||
|
||||
public String handleNoAnnotation() {
|
||||
@@ -627,11 +647,10 @@ public class SendToMethodReturnValueHandlerTests {
|
||||
return PAYLOAD;
|
||||
}
|
||||
|
||||
@SendToUser({"/dest3", "/dest4"})
|
||||
@MySendToUser(dest = {"/dest3", "/dest4"})
|
||||
public String handleAndSendToOverride() {
|
||||
return PAYLOAD;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,13 +21,12 @@ import java.lang.reflect.Method;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.core.annotation.AnnotationUtils.*;
|
||||
|
||||
/**
|
||||
* General utility methods for working with <em>profile values</em>.
|
||||
*
|
||||
@@ -49,12 +48,10 @@ public abstract class ProfileValueUtils {
|
||||
* {@link ProfileValueSourceConfiguration
|
||||
* @ProfileValueSourceConfiguration} annotation and instantiates a new
|
||||
* instance of that type.
|
||||
* <p>
|
||||
* If {@link ProfileValueSourceConfiguration
|
||||
* <p>If {@link ProfileValueSourceConfiguration
|
||||
* @ProfileValueSourceConfiguration} is not present on the specified
|
||||
* class or if a custom {@link ProfileValueSource} is not declared, the
|
||||
* default {@link SystemProfileValueSource} will be returned instead.
|
||||
*
|
||||
* @param testClass The test class for which the ProfileValueSource should
|
||||
* be retrieved
|
||||
* @return the configured (or default) ProfileValueSource for the specified
|
||||
@@ -66,10 +63,10 @@ public abstract class ProfileValueUtils {
|
||||
Assert.notNull(testClass, "testClass must not be null");
|
||||
|
||||
Class<ProfileValueSourceConfiguration> annotationType = ProfileValueSourceConfiguration.class;
|
||||
ProfileValueSourceConfiguration config = findAnnotation(testClass, annotationType);
|
||||
ProfileValueSourceConfiguration config = AnnotatedElementUtils.findMergedAnnotation(testClass, annotationType);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Retrieved @ProfileValueSourceConfiguration [" + config + "] for test class ["
|
||||
+ testClass.getName() + "]");
|
||||
logger.debug("Retrieved @ProfileValueSourceConfiguration [" + config + "] for test class [" +
|
||||
testClass.getName() + "]");
|
||||
}
|
||||
|
||||
Class<? extends ProfileValueSource> profileValueSourceType;
|
||||
@@ -80,8 +77,8 @@ public abstract class ProfileValueUtils {
|
||||
profileValueSourceType = (Class<? extends ProfileValueSource>) AnnotationUtils.getDefaultValue(annotationType);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Retrieved ProfileValueSource type [" + profileValueSourceType + "] for class ["
|
||||
+ testClass.getName() + "]");
|
||||
logger.debug("Retrieved ProfileValueSource type [" + profileValueSourceType + "] for class [" +
|
||||
testClass.getName() + "]");
|
||||
}
|
||||
|
||||
ProfileValueSource profileValueSource;
|
||||
@@ -92,10 +89,10 @@ public abstract class ProfileValueUtils {
|
||||
try {
|
||||
profileValueSource = profileValueSourceType.newInstance();
|
||||
}
|
||||
catch (Exception e) {
|
||||
catch (Exception ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Could not instantiate a ProfileValueSource of type [" + profileValueSourceType
|
||||
+ "] for class [" + testClass.getName() + "]: using default.", e);
|
||||
logger.warn("Could not instantiate a ProfileValueSource of type [" + profileValueSourceType +
|
||||
"] for class [" + testClass.getName() + "]: using default.", ex);
|
||||
}
|
||||
profileValueSource = SystemProfileValueSource.getInstance();
|
||||
}
|
||||
@@ -108,16 +105,14 @@ public abstract class ProfileValueUtils {
|
||||
* Determine if the supplied {@code testClass} is <em>enabled</em> in
|
||||
* the current environment, as specified by the {@link IfProfileValue
|
||||
* @IfProfileValue} annotation at the class level.
|
||||
* <p>
|
||||
* Defaults to {@code true} if no {@link IfProfileValue
|
||||
* <p>Defaults to {@code true} if no {@link IfProfileValue
|
||||
* @IfProfileValue} annotation is declared.
|
||||
*
|
||||
* @param testClass the test class
|
||||
* @return {@code true} if the test is <em>enabled</em> in the current
|
||||
* environment
|
||||
*/
|
||||
public static boolean isTestEnabledInThisEnvironment(Class<?> testClass) {
|
||||
IfProfileValue ifProfileValue = findAnnotation(testClass, IfProfileValue.class);
|
||||
IfProfileValue ifProfileValue = AnnotatedElementUtils.findMergedAnnotation(testClass, IfProfileValue.class);
|
||||
return isTestEnabledInThisEnvironment(retrieveProfileValueSource(testClass), ifProfileValue);
|
||||
}
|
||||
|
||||
@@ -127,10 +122,8 @@ public abstract class ProfileValueUtils {
|
||||
* @IfProfileValue} annotation, which may be declared on the test
|
||||
* method itself or at the class level. Class-level usage overrides
|
||||
* method-level usage.
|
||||
* <p>
|
||||
* Defaults to {@code true} if no {@link IfProfileValue
|
||||
* <p>Defaults to {@code true} if no {@link IfProfileValue
|
||||
* @IfProfileValue} annotation is declared.
|
||||
*
|
||||
* @param testMethod the test method
|
||||
* @param testClass the test class
|
||||
* @return {@code true} if the test is <em>enabled</em> in the current
|
||||
@@ -146,10 +139,8 @@ public abstract class ProfileValueUtils {
|
||||
* @IfProfileValue} annotation, which may be declared on the test
|
||||
* method itself or at the class level. Class-level usage overrides
|
||||
* method-level usage.
|
||||
* <p>
|
||||
* Defaults to {@code true} if no {@link IfProfileValue
|
||||
* <p>Defaults to {@code true} if no {@link IfProfileValue
|
||||
* @IfProfileValue} annotation is declared.
|
||||
*
|
||||
* @param profileValueSource the ProfileValueSource to use to determine if
|
||||
* the test is enabled
|
||||
* @param testMethod the test method
|
||||
@@ -160,11 +151,11 @@ public abstract class ProfileValueUtils {
|
||||
public static boolean isTestEnabledInThisEnvironment(ProfileValueSource profileValueSource, Method testMethod,
|
||||
Class<?> testClass) {
|
||||
|
||||
IfProfileValue ifProfileValue = findAnnotation(testClass, IfProfileValue.class);
|
||||
IfProfileValue ifProfileValue = AnnotatedElementUtils.findMergedAnnotation(testClass, IfProfileValue.class);
|
||||
boolean classLevelEnabled = isTestEnabledInThisEnvironment(profileValueSource, ifProfileValue);
|
||||
|
||||
if (classLevelEnabled) {
|
||||
ifProfileValue = findAnnotation(testMethod, IfProfileValue.class);
|
||||
ifProfileValue = AnnotatedElementUtils.findMergedAnnotation(testMethod, IfProfileValue.class);
|
||||
return isTestEnabledInThisEnvironment(profileValueSource, ifProfileValue);
|
||||
}
|
||||
|
||||
@@ -175,7 +166,6 @@ public abstract class ProfileValueUtils {
|
||||
* Determine if the {@code value} (or one of the {@code values})
|
||||
* in the supplied {@link IfProfileValue @IfProfileValue} annotation is
|
||||
* <em>enabled</em> in the current environment.
|
||||
*
|
||||
* @param profileValueSource the ProfileValueSource to use to determine if
|
||||
* the test is enabled
|
||||
* @param ifProfileValue the annotation to introspect; may be
|
||||
@@ -195,8 +185,8 @@ public abstract class ProfileValueUtils {
|
||||
String[] annotatedValues = ifProfileValue.values();
|
||||
if (StringUtils.hasLength(ifProfileValue.value())) {
|
||||
if (annotatedValues.length > 0) {
|
||||
throw new IllegalArgumentException("Setting both the 'value' and 'values' attributes "
|
||||
+ "of @IfProfileValue is not allowed: choose one or the other.");
|
||||
throw new IllegalArgumentException("Setting both the 'value' and 'values' attributes " +
|
||||
"of @IfProfileValue is not allowed: choose one or the other.");
|
||||
}
|
||||
annotatedValues = new String[] { ifProfileValue.value() };
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +19,6 @@ package org.springframework.test.annotation;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
|
||||
/**
|
||||
* Collection of utility methods for working with Spring's core testing annotations.
|
||||
@@ -52,7 +51,7 @@ public class TestAnnotationUtils {
|
||||
* not annotated with {@code @Repeat}
|
||||
*/
|
||||
public static int getRepeatCount(Method method) {
|
||||
Repeat repeat = AnnotationUtils.findAnnotation(method, Repeat.class);
|
||||
Repeat repeat = AnnotatedElementUtils.findMergedAnnotation(method, Repeat.class);
|
||||
if (repeat == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,7 @@ import java.lang.reflect.Method;
|
||||
import org.junit.AssumptionViolatedException;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.test.annotation.IfProfileValue;
|
||||
import org.springframework.test.annotation.ProfileValueUtils;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -64,6 +64,7 @@ public class ProfileValueChecker extends Statement {
|
||||
this.testMethod = testMethod;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the test specified by arguments to the
|
||||
* {@linkplain #ProfileValueChecker constructor} is <em>enabled</em> in
|
||||
@@ -83,17 +84,17 @@ public class ProfileValueChecker extends Statement {
|
||||
public void evaluate() throws Throwable {
|
||||
if (this.testMethod == null) {
|
||||
if (!ProfileValueUtils.isTestEnabledInThisEnvironment(this.testClass)) {
|
||||
Annotation ann = AnnotationUtils.findAnnotation(this.testClass, IfProfileValue.class);
|
||||
throw new AssumptionViolatedException(
|
||||
String.format("Profile configured via [%s] is not enabled in this environment for test class [%s].",
|
||||
Annotation ann = AnnotatedElementUtils.findMergedAnnotation(this.testClass, IfProfileValue.class);
|
||||
throw new AssumptionViolatedException(String.format(
|
||||
"Profile configured via [%s] is not enabled in this environment for test class [%s].",
|
||||
ann, this.testClass.getName()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!ProfileValueUtils.isTestEnabledInThisEnvironment(this.testMethod, this.testClass)) {
|
||||
throw new AssumptionViolatedException(String.format(
|
||||
"Profile configured via @IfProfileValue is not enabled in this environment for test method [%s].",
|
||||
this.testMethod));
|
||||
"Profile configured via @IfProfileValue is not enabled in this environment for test method [%s].",
|
||||
this.testMethod));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeanInstantiationException;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.test.context.BootstrapContext;
|
||||
import org.springframework.test.context.CacheAwareContextLoaderDelegate;
|
||||
@@ -278,7 +278,7 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
|
||||
return buildDefaultMergedContextConfiguration(testClass, cacheAwareContextLoaderDelegate);
|
||||
}
|
||||
|
||||
if (AnnotationUtils.findAnnotation(testClass, ContextHierarchy.class) != null) {
|
||||
if (AnnotatedElementUtils.findMergedAnnotation(testClass, ContextHierarchy.class) != null) {
|
||||
Map<String, List<ContextConfigurationAttributes>> hierarchyMap = ContextLoaderUtils.buildContextHierarchyMap(testClass);
|
||||
MergedContextConfiguration parentConfig = null;
|
||||
MergedContextConfiguration mergedConfig = null;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,7 +24,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.test.context.SmartContextLoader;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -103,7 +103,7 @@ public abstract class AnnotationConfigContextLoaderUtils {
|
||||
*/
|
||||
private static boolean isDefaultConfigurationClassCandidate(Class<?> clazz) {
|
||||
return (clazz != null && isStaticNonPrivateAndNonFinal(clazz) &&
|
||||
(AnnotationUtils.findAnnotation(clazz, Configuration.class) != null));
|
||||
AnnotatedElementUtils.hasAnnotation(clazz, Configuration.class));
|
||||
}
|
||||
|
||||
private static boolean isStaticNonPrivateAndNonFinal(Class<?> clazz) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -95,11 +95,10 @@ abstract class ContextLoaderUtils {
|
||||
@SuppressWarnings("unchecked")
|
||||
static List<List<ContextConfigurationAttributes>> resolveContextHierarchyAttributes(Class<?> testClass) {
|
||||
Assert.notNull(testClass, "Class must not be null");
|
||||
Assert.state(findAnnotation(testClass, ContextHierarchy.class) != null, "@ContextHierarchy must be present");
|
||||
|
||||
final Class<ContextConfiguration> contextConfigType = ContextConfiguration.class;
|
||||
final Class<ContextHierarchy> contextHierarchyType = ContextHierarchy.class;
|
||||
final List<List<ContextConfigurationAttributes>> hierarchyAttributes = new ArrayList<List<ContextConfigurationAttributes>>();
|
||||
Class<ContextConfiguration> contextConfigType = ContextConfiguration.class;
|
||||
Class<ContextHierarchy> contextHierarchyType = ContextHierarchy.class;
|
||||
List<List<ContextConfigurationAttributes>> hierarchyAttributes = new ArrayList<List<ContextConfigurationAttributes>>();
|
||||
|
||||
UntypedAnnotationDescriptor desc =
|
||||
findAnnotationDescriptorForTypes(testClass, contextConfigType, contextHierarchyType);
|
||||
@@ -124,7 +123,7 @@ abstract class ContextLoaderUtils {
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
|
||||
final List<ContextConfigurationAttributes> configAttributesList = new ArrayList<ContextConfigurationAttributes>();
|
||||
List<ContextConfigurationAttributes> configAttributesList = new ArrayList<ContextConfigurationAttributes>();
|
||||
|
||||
if (contextConfigDeclaredLocally) {
|
||||
ContextConfiguration contextConfiguration = AnnotationUtils.synthesizeAnnotation(
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.test.annotation.Commit;
|
||||
import org.springframework.test.annotation.Rollback;
|
||||
import org.springframework.test.context.TestContext;
|
||||
@@ -44,9 +45,6 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
|
||||
import static org.springframework.core.annotation.AnnotationUtils.getAnnotation;
|
||||
|
||||
/**
|
||||
* {@code TestExecutionListener} that provides support for executing tests
|
||||
* within <em>test-managed transactions</em> by honoring Spring's
|
||||
@@ -181,8 +179,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
transactionAttribute);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Explicit transaction definition [" + transactionAttribute + "] found for test context "
|
||||
+ testContext);
|
||||
logger.debug("Explicit transaction definition [" + transactionAttribute + "] found for test context " +
|
||||
testContext);
|
||||
}
|
||||
|
||||
if (transactionAttribute.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
|
||||
@@ -193,8 +191,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
|
||||
if (tm == null) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"Failed to retrieve PlatformTransactionManager for @Transactional test for test context %s.",
|
||||
testContext));
|
||||
"Failed to retrieve PlatformTransactionManager for @Transactional test for test context %s.",
|
||||
testContext));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,8 +253,10 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
}
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
logger.error("Exception encountered while executing @BeforeTransaction methods for test context "
|
||||
+ testContext + ".", ex.getTargetException());
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error("Exception encountered while executing @BeforeTransaction methods for test context " +
|
||||
testContext + ".", ex.getTargetException());
|
||||
}
|
||||
ReflectionUtils.rethrowException(ex.getTargetException());
|
||||
}
|
||||
}
|
||||
@@ -286,15 +286,15 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
if (afterTransactionException == null) {
|
||||
afterTransactionException = targetException;
|
||||
}
|
||||
logger.error("Exception encountered while executing @AfterTransaction method [" + method
|
||||
+ "] for test context " + testContext, targetException);
|
||||
logger.error("Exception encountered while executing @AfterTransaction method [" + method +
|
||||
"] for test context " + testContext, targetException);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (afterTransactionException == null) {
|
||||
afterTransactionException = ex;
|
||||
}
|
||||
logger.error("Exception encountered while executing @AfterTransaction method [" + method
|
||||
+ "] for test context " + testContext, ex);
|
||||
logger.error("Exception encountered while executing @AfterTransaction method [" + method +
|
||||
"] for test context " + testContext, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,20 +317,18 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
* @see #getTransactionManager(TestContext)
|
||||
*/
|
||||
protected PlatformTransactionManager getTransactionManager(TestContext testContext, String qualifier) {
|
||||
// look up by type and qualifier from @Transactional
|
||||
// Look up by type and qualifier from @Transactional
|
||||
if (StringUtils.hasText(qualifier)) {
|
||||
try {
|
||||
// Use autowire-capable factory in order to support extended qualifier
|
||||
// matching (only exposed on the internal BeanFactory, not on the
|
||||
// ApplicationContext).
|
||||
// Use autowire-capable factory in order to support extended qualifier matching
|
||||
// (only exposed on the internal BeanFactory, not on the ApplicationContext).
|
||||
BeanFactory bf = testContext.getApplicationContext().getAutowireCapableBeanFactory();
|
||||
|
||||
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(bf, PlatformTransactionManager.class, qualifier);
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(
|
||||
String.format(
|
||||
logger.warn(String.format(
|
||||
"Caught exception while retrieving transaction manager with qualifier '%s' for test context %s",
|
||||
qualifier, testContext), ex);
|
||||
}
|
||||
@@ -376,7 +374,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
@SuppressWarnings("deprecation")
|
||||
protected final boolean isDefaultRollback(TestContext testContext) throws Exception {
|
||||
Class<?> testClass = testContext.getTestClass();
|
||||
Rollback rollback = findAnnotation(testClass, Rollback.class);
|
||||
Rollback rollback = AnnotatedElementUtils.findMergedAnnotation(testClass, Rollback.class);
|
||||
boolean rollbackPresent = (rollback != null);
|
||||
TransactionConfigurationAttributes txConfigAttributes = retrieveConfigurationAttributes(testContext);
|
||||
|
||||
@@ -411,21 +409,22 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
*/
|
||||
protected final boolean isRollback(TestContext testContext) throws Exception {
|
||||
boolean rollback = isDefaultRollback(testContext);
|
||||
Rollback rollbackAnnotation = findAnnotation(testContext.getTestMethod(), Rollback.class);
|
||||
Rollback rollbackAnnotation =
|
||||
AnnotatedElementUtils.findMergedAnnotation(testContext.getTestMethod(), Rollback.class);
|
||||
if (rollbackAnnotation != null) {
|
||||
boolean rollbackOverride = rollbackAnnotation.value();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format(
|
||||
"Method-level @Rollback(%s) overrides default rollback [%s] for test context %s.",
|
||||
rollbackOverride, rollback, testContext));
|
||||
"Method-level @Rollback(%s) overrides default rollback [%s] for test context %s.",
|
||||
rollbackOverride, rollback, testContext));
|
||||
}
|
||||
rollback = rollbackOverride;
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format(
|
||||
"No method-level @Rollback override: using default rollback [%s] for test context %s.", rollback,
|
||||
testContext));
|
||||
"No method-level @Rollback override: using default rollback [%s] for test context %s.",
|
||||
rollback, testContext));
|
||||
}
|
||||
}
|
||||
return rollback;
|
||||
@@ -466,7 +465,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
List<Method> results = new ArrayList<Method>();
|
||||
for (Class<?> current : getSuperClasses(clazz)) {
|
||||
for (Method method : current.getDeclaredMethods()) {
|
||||
Annotation annotation = getAnnotation(method, annotationType);
|
||||
Annotation annotation = AnnotationUtils.getAnnotation(method, annotationType);
|
||||
if (annotation != null && !isShadowed(method, results)) {
|
||||
results.add(method);
|
||||
}
|
||||
@@ -537,19 +536,18 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
if (this.configurationAttributes == null) {
|
||||
Class<?> clazz = testContext.getTestClass();
|
||||
|
||||
TransactionConfiguration txConfig = AnnotatedElementUtils.findMergedAnnotation(clazz,
|
||||
TransactionConfiguration.class);
|
||||
TransactionConfiguration txConfig =
|
||||
AnnotatedElementUtils.findMergedAnnotation(clazz, TransactionConfiguration.class);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Retrieved @TransactionConfiguration [%s] for test class [%s].",
|
||||
txConfig, clazz.getName()));
|
||||
txConfig, clazz.getName()));
|
||||
}
|
||||
|
||||
TransactionConfigurationAttributes configAttributes = (txConfig == null ? defaultTxConfigAttributes
|
||||
: new TransactionConfigurationAttributes(txConfig.transactionManager(), txConfig.defaultRollback()));
|
||||
|
||||
TransactionConfigurationAttributes configAttributes = (txConfig == null ? defaultTxConfigAttributes :
|
||||
new TransactionConfigurationAttributes(txConfig.transactionManager(), txConfig.defaultRollback()));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Using TransactionConfigurationAttributes %s for test class [%s].",
|
||||
configAttributes, clazz.getName()));
|
||||
configAttributes, clazz.getName()));
|
||||
}
|
||||
this.configurationAttributes = configAttributes;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.Conventions;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
@@ -33,7 +33,6 @@ import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.TestExecutionListener;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
@@ -58,7 +57,7 @@ import org.springframework.web.context.request.ServletWebRequest;
|
||||
* <p>Note that {@code ServletTestExecutionListener} is enabled by default but
|
||||
* generally takes no action if the {@linkplain TestContext#getTestClass() test
|
||||
* class} is not annotated with {@link WebAppConfiguration @WebAppConfiguration}.
|
||||
* See the Javadoc for individual methods in this class for details.
|
||||
* See the javadocs for individual methods in this class for details.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Phillip Webb
|
||||
@@ -71,45 +70,41 @@ public class ServletTestExecutionListener extends AbstractTestExecutionListener
|
||||
* whether or not the {@code ServletTestExecutionListener} should {@linkplain
|
||||
* RequestContextHolder#resetRequestAttributes() reset} Spring Web's
|
||||
* {@code RequestContextHolder} in {@link #afterTestMethod(TestContext)}.
|
||||
*
|
||||
* <p>Permissible values include {@link Boolean#TRUE} and {@link Boolean#FALSE}.
|
||||
*/
|
||||
public static final String RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE = Conventions.getQualifiedAttributeName(
|
||||
ServletTestExecutionListener.class, "resetRequestContextHolder");
|
||||
ServletTestExecutionListener.class, "resetRequestContextHolder");
|
||||
|
||||
/**
|
||||
* Attribute name for a {@link TestContext} attribute which indicates that
|
||||
* {@code ServletTestExecutionListener} has already populated Spring Web's
|
||||
* {@code RequestContextHolder}.
|
||||
*
|
||||
* <p>Permissible values include {@link Boolean#TRUE} and {@link Boolean#FALSE}.
|
||||
*/
|
||||
public static final String POPULATED_REQUEST_CONTEXT_HOLDER_ATTRIBUTE = Conventions.getQualifiedAttributeName(
|
||||
ServletTestExecutionListener.class, "populatedRequestContextHolder");
|
||||
ServletTestExecutionListener.class, "populatedRequestContextHolder");
|
||||
|
||||
/**
|
||||
* Attribute name for a request attribute which indicates that the
|
||||
* {@link MockHttpServletRequest} stored in the {@link RequestAttributes}
|
||||
* in Spring Web's {@link RequestContextHolder} was created by the TestContext
|
||||
* framework.
|
||||
*
|
||||
* <p>Permissible values include {@link Boolean#TRUE} and {@link Boolean#FALSE}.
|
||||
* @since 4.2
|
||||
*/
|
||||
public static final String CREATED_BY_THE_TESTCONTEXT_FRAMEWORK = Conventions.getQualifiedAttributeName(
|
||||
ServletTestExecutionListener.class, "createdByTheTestContextFramework");
|
||||
ServletTestExecutionListener.class, "createdByTheTestContextFramework");
|
||||
|
||||
/**
|
||||
* Attribute name for a {@link TestContext} attribute which indicates that that
|
||||
* the {@code ServletTestExecutionListener} should be activated. When not set to
|
||||
* {@code true}, activation occurs when the {@linkplain TestContext#getTestClass()
|
||||
* test class} is annotated with {@link WebAppConfiguration @WebAppConfiguration}.
|
||||
*
|
||||
* <p>Permissible values include {@link Boolean#TRUE} and {@link Boolean#FALSE}.
|
||||
* @since 4.3
|
||||
*/
|
||||
public static final String ACTIVATE_LISTENER = Conventions.getQualifiedAttributeName(
|
||||
ServletTestExecutionListener.class, "activateListener");
|
||||
ServletTestExecutionListener.class, "activateListener");
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ServletTestExecutionListener.class);
|
||||
|
||||
@@ -181,8 +176,8 @@ public class ServletTestExecutionListener extends AbstractTestExecutionListener
|
||||
}
|
||||
|
||||
private boolean isActivated(TestContext testContext) {
|
||||
return (Boolean.TRUE.equals(testContext.getAttribute(ACTIVATE_LISTENER))
|
||||
|| AnnotationUtils.findAnnotation(testContext.getTestClass(), WebAppConfiguration.class) != null);
|
||||
return (Boolean.TRUE.equals(testContext.getAttribute(ACTIVATE_LISTENER)) ||
|
||||
AnnotatedElementUtils.hasAnnotation(testContext.getTestClass(), WebAppConfiguration.class));
|
||||
}
|
||||
|
||||
private boolean alreadyPopulatedRequestContextHolder(TestContext testContext) {
|
||||
@@ -199,14 +194,16 @@ public class ServletTestExecutionListener extends AbstractTestExecutionListener
|
||||
if (context instanceof WebApplicationContext) {
|
||||
WebApplicationContext wac = (WebApplicationContext) context;
|
||||
ServletContext servletContext = wac.getServletContext();
|
||||
Assert.state(servletContext instanceof MockServletContext, String.format(
|
||||
"The WebApplicationContext for test context %s must be configured with a MockServletContext.",
|
||||
testContext));
|
||||
if (!(servletContext instanceof MockServletContext)) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"The WebApplicationContext for test context %s must be configured with a MockServletContext.",
|
||||
testContext));
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format(
|
||||
"Setting up MockHttpServletRequest, MockHttpServletResponse, ServletWebRequest, and RequestContextHolder for test context %s.",
|
||||
testContext));
|
||||
"Setting up MockHttpServletRequest, MockHttpServletResponse, ServletWebRequest, and RequestContextHolder for test context %s.",
|
||||
testContext));
|
||||
}
|
||||
|
||||
MockServletContext mockServletContext = (MockServletContext) servletContext;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.test.context.web;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.test.context.ContextLoader;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.test.context.TestContextBootstrapper;
|
||||
@@ -45,12 +45,12 @@ public class WebTestContextBootstrapper extends DefaultTestContextBootstrapper {
|
||||
*/
|
||||
@Override
|
||||
protected Class<? extends ContextLoader> getDefaultContextLoaderClass(Class<?> testClass) {
|
||||
if (AnnotationUtils.findAnnotation(testClass, WebAppConfiguration.class) != null) {
|
||||
if (AnnotatedElementUtils.findMergedAnnotation(testClass, WebAppConfiguration.class) != null) {
|
||||
return WebDelegatingSmartContextLoader.class;
|
||||
}
|
||||
|
||||
// else...
|
||||
return super.getDefaultContextLoaderClass(testClass);
|
||||
else {
|
||||
return super.getDefaultContextLoaderClass(testClass);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,14 +61,14 @@ public class WebTestContextBootstrapper extends DefaultTestContextBootstrapper {
|
||||
*/
|
||||
@Override
|
||||
protected MergedContextConfiguration processMergedContextConfiguration(MergedContextConfiguration mergedConfig) {
|
||||
WebAppConfiguration webAppConfiguration = AnnotationUtils.findAnnotation(mergedConfig.getTestClass(),
|
||||
WebAppConfiguration.class);
|
||||
WebAppConfiguration webAppConfiguration =
|
||||
AnnotatedElementUtils.findMergedAnnotation(mergedConfig.getTestClass(), WebAppConfiguration.class);
|
||||
if (webAppConfiguration != null) {
|
||||
return new WebMergedContextConfiguration(mergedConfig, webAppConfiguration.value());
|
||||
}
|
||||
|
||||
// else...
|
||||
return mergedConfig;
|
||||
else {
|
||||
return mergedConfig;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
@@ -60,6 +61,7 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextConf
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
@Ignore // an upfront findAnnotation check just for an assertion seems too expensive
|
||||
public void resolveContextHierarchyAttributesForSingleTestClassWithImplicitSingleLevelContextHierarchy() {
|
||||
resolveContextHierarchyAttributes(BareAnnotations.class);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -54,7 +54,10 @@ class ApplicationListenerMethodTransactionalAdapter extends ApplicationListenerM
|
||||
|
||||
public ApplicationListenerMethodTransactionalAdapter(String beanName, Class<?> targetClass, Method method) {
|
||||
super(beanName, targetClass, method);
|
||||
this.annotation = findAnnotation(method);
|
||||
this.annotation = AnnotatedElementUtils.findMergedAnnotation(method, TransactionalEventListener.class);
|
||||
if (this.annotation == null) {
|
||||
throw new IllegalStateException("No TransactionalEventListener annotation found on '" + method + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,14 +84,6 @@ class ApplicationListenerMethodTransactionalAdapter extends ApplicationListenerM
|
||||
return new TransactionSynchronizationEventAdapter(this, event, this.annotation.phase());
|
||||
}
|
||||
|
||||
static TransactionalEventListener findAnnotation(Method method) {
|
||||
TransactionalEventListener annotation =
|
||||
AnnotatedElementUtils.findMergedAnnotation(method, TransactionalEventListener.class);
|
||||
if (annotation == null) {
|
||||
throw new IllegalStateException("No TransactionalEventListener annotation found on '" + method + "'");
|
||||
}
|
||||
return annotation;
|
||||
}
|
||||
|
||||
|
||||
private static class TransactionSynchronizationEventAdapter extends TransactionSynchronizationAdapter {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,6 +25,7 @@ import org.junit.rules.ExpectedException;
|
||||
import org.springframework.context.PayloadApplicationEvent;
|
||||
import org.springframework.context.event.ApplicationListenerMethodAdapter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
@@ -37,15 +38,6 @@ public class ApplicationListenerMethodTransactionalAdapterTests {
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void noAnnotation() {
|
||||
Method m = ReflectionUtils.findMethod(SampleEvents.class,
|
||||
"noAnnotation", String.class);
|
||||
|
||||
thrown.expect(IllegalStateException.class);
|
||||
thrown.expectMessage("noAnnotation");
|
||||
ApplicationListenerMethodTransactionalAdapter.findAnnotation(m);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultPhase() {
|
||||
@@ -78,7 +70,8 @@ public class ApplicationListenerMethodTransactionalAdapterTests {
|
||||
|
||||
private void assertPhase(Method method, TransactionPhase expected) {
|
||||
assertNotNull("Method must not be null", method);
|
||||
TransactionalEventListener annotation = ApplicationListenerMethodTransactionalAdapter.findAnnotation(method);
|
||||
TransactionalEventListener annotation =
|
||||
AnnotatedElementUtils.findMergedAnnotation(method, TransactionalEventListener.class);
|
||||
assertEquals("Wrong phase for '" + method + "'", expected, annotation.phase());
|
||||
}
|
||||
|
||||
@@ -96,10 +89,8 @@ public class ApplicationListenerMethodTransactionalAdapterTests {
|
||||
return ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, payloadType);
|
||||
}
|
||||
|
||||
static class SampleEvents {
|
||||
|
||||
public void noAnnotation(String data) {
|
||||
}
|
||||
static class SampleEvents {
|
||||
|
||||
@TransactionalEventListener
|
||||
public void defaultPhase(String data) {
|
||||
@@ -117,7 +108,6 @@ public class ApplicationListenerMethodTransactionalAdapterTests {
|
||||
@TransactionalEventListener(String.class)
|
||||
public void valueSet() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ public class HandlerMethod {
|
||||
* if no annotation can be found on the given method itself.
|
||||
* <p>Also supports <em>merged</em> composed annotations with attribute
|
||||
* overrides as of Spring Framework 4.2.2.
|
||||
* @param annotationType the type of annotation to introspect the method for.
|
||||
* @param annotationType the type of annotation to introspect the method for
|
||||
* @return the annotation, or {@code null} if none found
|
||||
* @see AnnotatedElementUtils#findMergedAnnotation
|
||||
*/
|
||||
@@ -234,6 +234,16 @@ public class HandlerMethod {
|
||||
return AnnotatedElementUtils.findMergedAnnotation(this.method, annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the parameter is declared with the given annotation type.
|
||||
* @param annotationType the annotation type to look for
|
||||
* @since 4.3
|
||||
* @see AnnotatedElementUtils#hasAnnotation
|
||||
*/
|
||||
public <A extends Annotation> boolean hasMethodAnnotation(Class<A> annotationType) {
|
||||
return AnnotatedElementUtils.hasAnnotation(this.method, annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the provided instance contains a bean name rather than an object instance,
|
||||
* the bean name is resolved before a {@link HandlerMethod} is created and returned.
|
||||
@@ -247,6 +257,15 @@ public class HandlerMethod {
|
||||
return new HandlerMethod(this, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a short representation of this handler method for log message purposes.
|
||||
* @since 4.3
|
||||
*/
|
||||
public String getShortLogMessage() {
|
||||
int args = this.method.getParameterTypes().length;
|
||||
return getBeanType().getName() + "#" + this.method.getName() + "[" + args + " args]";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
@@ -294,6 +313,11 @@ public class HandlerMethod {
|
||||
return HandlerMethod.this.getMethodAnnotation(annotationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Annotation> boolean hasMethodAnnotation(Class<T> annotationType) {
|
||||
return HandlerMethod.this.hasMethodAnnotation(annotationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerMethodParameter clone() {
|
||||
return new HandlerMethodParameter(this);
|
||||
|
||||
@@ -102,8 +102,8 @@ public class ModelAttributeMethodProcessor
|
||||
createAttribute(name, parameter, binderFactory, webRequest));
|
||||
|
||||
if (!mavContainer.isBindingDisabled(name)) {
|
||||
ModelAttribute annotation = parameter.getParameterAnnotation(ModelAttribute.class);
|
||||
if (annotation != null && !annotation.binding()) {
|
||||
ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
|
||||
if (ann != null && !ann.binding()) {
|
||||
mavContainer.setBindingDisabled(name);
|
||||
}
|
||||
}
|
||||
@@ -192,8 +192,8 @@ public class ModelAttributeMethodProcessor
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsReturnType(MethodParameter returnType) {
|
||||
return (returnType.getMethodAnnotation(ModelAttribute.class) != null ||
|
||||
this.annotationNotRequired && !BeanUtils.isSimpleProperty(returnType.getParameterType()));
|
||||
return (returnType.hasMethodAnnotation(ModelAttribute.class) ||
|
||||
(this.annotationNotRequired && !BeanUtils.isSimpleProperty(returnType.getParameterType())));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,7 +24,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||
import org.springframework.web.bind.support.SessionAttributeStore;
|
||||
@@ -65,10 +65,11 @@ public class SessionAttributesHandler {
|
||||
* @param sessionAttributeStore used for session access
|
||||
*/
|
||||
public SessionAttributesHandler(Class<?> handlerType, SessionAttributeStore sessionAttributeStore) {
|
||||
Assert.notNull(sessionAttributeStore, "SessionAttributeStore may not be null.");
|
||||
Assert.notNull(sessionAttributeStore, "SessionAttributeStore may not be null");
|
||||
this.sessionAttributeStore = sessionAttributeStore;
|
||||
|
||||
SessionAttributes annotation = AnnotationUtils.findAnnotation(handlerType, SessionAttributes.class);
|
||||
SessionAttributes annotation =
|
||||
AnnotatedElementUtils.findMergedAnnotation(handlerType, SessionAttributes.class);
|
||||
if (annotation != null) {
|
||||
this.attributeNames.addAll(Arrays.asList(annotation.names()));
|
||||
this.attributeTypes.addAll(Arrays.asList(annotation.types()));
|
||||
@@ -84,7 +85,7 @@ public class SessionAttributesHandler {
|
||||
* session attributes through an {@link SessionAttributes} annotation.
|
||||
*/
|
||||
public boolean hasSessionAttributes() {
|
||||
return ((this.attributeNames.size() > 0) || (this.attributeTypes.size() > 0));
|
||||
return (this.attributeNames.size() > 0 || this.attributeTypes.size() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -47,7 +47,7 @@ public class JsonViewResponseBodyAdvice extends AbstractMappingJacksonResponseBo
|
||||
|
||||
@Override
|
||||
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
return (super.supports(returnType, converterType) && returnType.getMethodAnnotation(JsonView.class) != null);
|
||||
return super.supports(returnType, converterType) && returnType.hasMethodAnnotation(JsonView.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.util.List;
|
||||
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -168,8 +167,8 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
||||
*/
|
||||
@Override
|
||||
protected boolean isHandler(Class<?> beanType) {
|
||||
return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||
|
||||
(AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));
|
||||
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
|
||||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,7 +23,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.core.Conventions;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpRange;
|
||||
@@ -114,8 +114,8 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
|
||||
|
||||
@Override
|
||||
public boolean supportsReturnType(MethodParameter returnType) {
|
||||
return (AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null ||
|
||||
returnType.getMethodAnnotation(ResponseBody.class) != null);
|
||||
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
|
||||
returnType.hasMethodAnnotation(ResponseBody.class));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,14 +173,15 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
|
||||
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
|
||||
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
|
||||
|
||||
if(inputMessage.getHeaders().containsKey(HttpHeaders.RANGE) &&
|
||||
if (inputMessage.getHeaders().containsKey(HttpHeaders.RANGE) &&
|
||||
Resource.class.isAssignableFrom(returnValue.getClass())) {
|
||||
try {
|
||||
List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
|
||||
Resource bodyResource = (Resource) returnValue;
|
||||
returnValue = new HttpRangeResource(httpRanges, bodyResource);
|
||||
outputMessage.setStatusCode(HttpStatus.PARTIAL_CONTENT);
|
||||
} catch (IllegalArgumentException exc) {
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
outputMessage.setStatusCode(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE);
|
||||
outputMessage.flush();
|
||||
return;
|
||||
|
||||
@@ -242,6 +242,14 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
|
||||
public <A extends Annotation> A getMethodAnnotation(Class<A> annotationType) {
|
||||
return ServletInvocableHandlerMethod.this.getMethodAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge to controller method-level annotations.
|
||||
*/
|
||||
@Override
|
||||
public <A extends Annotation> boolean hasMethodAnnotation(Class<A> annotationType) {
|
||||
return ServletInvocableHandlerMethod.this.hasMethodAnnotation(annotationType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user