Migrate to MergedAnnotations API

Migrate away from `AnnotationUtils` and `AnnotatedElementUtils`
when possible to the new `MergedAnnotations` API.

Closes gh-16551
This commit is contained in:
Phillip Webb
2019-04-18 11:18:10 -07:00
parent 3ecefdbcdc
commit b879972d0d
58 changed files with 560 additions and 860 deletions

View File

@@ -29,8 +29,7 @@ import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExten
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.MergedAnnotations;
/**
* {@link WebEndpointDiscoverer} for Cloud Foundry that uses Cloud Foundry specific
@@ -70,16 +69,14 @@ public class CloudFoundryWebEndpointDiscoverer extends WebEndpointDiscoverer {
}
private boolean isHealthEndpointExtension(Object extensionBean) {
AnnotationAttributes attributes = AnnotatedElementUtils
.getMergedAnnotationAttributes(extensionBean.getClass(),
EndpointWebExtension.class);
Class<?> endpoint = (attributes != null) ? attributes.getClass("endpoint") : null;
return (endpoint != null && HealthEndpoint.class.isAssignableFrom(endpoint));
return MergedAnnotations.from(extensionBean.getClass())
.get(EndpointWebExtension.class).getValue("endpoint", Class.class)
.map(HealthEndpoint.class::isAssignableFrom).orElse(false);
}
private boolean isCloudFoundryHealthEndpointExtension(Object extensionBean) {
return AnnotatedElementUtils.hasAnnotation(extensionBean.getClass(),
EndpointCloudFoundryExtension.class);
return MergedAnnotations.from(extensionBean.getClass())
.isPresent(EndpointCloudFoundryExtension.class);
}
}

View File

@@ -23,8 +23,10 @@ import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.util.Assert;
@@ -71,17 +73,18 @@ abstract class AbstractEndpointCondition extends SpringBootCondition {
}
AnnotationAttributes getEndpointAttributes(Class<?> type) {
AnnotationAttributes attributes = AnnotatedElementUtils
.findMergedAnnotationAttributes(type, Endpoint.class, true, true);
if (attributes != null) {
return attributes;
MergedAnnotations annotations = MergedAnnotations.from(type,
SearchStrategy.EXHAUSTIVE);
MergedAnnotation<Endpoint> endpoint = annotations.get(Endpoint.class);
if (endpoint.isPresent()) {
return endpoint.asAnnotationAttributes();
}
attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(type,
EndpointExtension.class, false, true);
Assert.state(attributes != null,
MergedAnnotation<EndpointExtension> extension = annotations
.get(EndpointExtension.class);
Assert.state(extension.isPresent(),
"No endpoint is specified and the return type of the @Bean method is "
+ "neither an @Endpoint, nor an @EndpointExtension");
return getEndpointAttributes(attributes.getClass("endpoint"));
return getEndpointAttributes(extension.getClass("endpoint"));
}
}

View File

@@ -37,7 +37,8 @@ import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
import org.springframework.boot.security.reactive.ApplicationContextServerWebExchangeMatcher;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.security.web.server.util.matcher.OrServerWebExchangeMatcher;
import org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
@@ -225,11 +226,11 @@ public final class EndpointRequest {
}
private EndpointId getEndpointId(Class<?> source) {
Endpoint annotation = AnnotatedElementUtils.getMergedAnnotation(source,
Endpoint.class);
Assert.state(annotation != null,
MergedAnnotation<Endpoint> annotation = MergedAnnotations.from(source)
.get(Endpoint.class);
Assert.state(annotation.isPresent(),
() -> "Class " + source + " is not annotated with @Endpoint");
return EndpointId.of(annotation.id());
return EndpointId.of(annotation.getString("id"));
}
private List<ServerWebExchangeMatcher> getDelegateMatchers(Set<String> paths) {

View File

@@ -37,7 +37,8 @@ import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
import org.springframework.boot.autoconfigure.security.servlet.RequestMatcherProvider;
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -275,11 +276,11 @@ public final class EndpointRequest {
}
private EndpointId getEndpointId(Class<?> source) {
Endpoint annotation = AnnotatedElementUtils.getMergedAnnotation(source,
Endpoint.class);
Assert.state(annotation != null,
MergedAnnotation<Endpoint> annotation = MergedAnnotations.from(source)
.get(Endpoint.class);
Assert.state(annotation.isPresent(),
() -> "Class " + source + " is not annotated with @Endpoint");
return EndpointId.of(annotation.id());
return EndpointId.of(annotation.getString("id"));
}
private List<RequestMatcher> getDelegateMatchers(

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -34,8 +34,8 @@ import org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;
import org.springframework.boot.actuate.endpoint.invoke.reflect.ReflectiveOperationInvoker;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.MethodIntrospector.MetadataLookup;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
/**
* Factory to create an {@link Operation} for annotated methods on an
@@ -84,13 +84,13 @@ abstract class DiscoveredOperationsFactory<O extends Operation> {
private O createOperation(EndpointId endpointId, Object target, Method method,
OperationType operationType, Class<? extends Annotation> annotationType) {
AnnotationAttributes annotationAttributes = AnnotatedElementUtils
.getMergedAnnotationAttributes(method, annotationType);
if (annotationAttributes == null) {
MergedAnnotation<?> annotation = MergedAnnotations.from(method)
.get(annotationType);
if (!annotation.isPresent()) {
return null;
}
DiscoveredOperationMethod operationMethod = new DiscoveredOperationMethod(method,
operationType, annotationAttributes);
operationType, annotation.asAnnotationAttributes());
OperationInvoker invoker = new ReflectiveOperationInvoker(target, operationMethod,
this.parameterValueMapper);
invoker = applyAdvisors(endpointId, operationMethod, invoker);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -44,8 +44,9 @@ import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;
import org.springframework.boot.util.LambdaSafe;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
@@ -429,17 +430,16 @@ public abstract class EndpointDiscoverer<E extends ExposableEndpoint<O>, O exten
private Set<ExtensionBean> extensions = new LinkedHashSet<>();
EndpointBean(String beanName, Object bean) {
AnnotationAttributes attributes = AnnotatedElementUtils
.findMergedAnnotationAttributes(bean.getClass(), Endpoint.class, true,
true);
String id = attributes.getString("id");
MergedAnnotation<Endpoint> annotation = MergedAnnotations
.from(bean.getClass(), SearchStrategy.EXHAUSTIVE).get(Endpoint.class);
String id = annotation.getString("id");
Assert.state(StringUtils.hasText(id),
() -> "No @Endpoint id attribute specified for "
+ bean.getClass().getName());
this.beanName = beanName;
this.bean = bean;
this.id = EndpointId.of(id);
this.enabledByDefault = (Boolean) attributes.get("enableByDefault");
this.enabledByDefault = annotation.getBoolean("enableByDefault");
this.filter = getFilter(this.bean.getClass());
}
@@ -452,12 +452,8 @@ public abstract class EndpointDiscoverer<E extends ExposableEndpoint<O>, O exten
}
private Class<?> getFilter(Class<?> type) {
AnnotationAttributes attributes = AnnotatedElementUtils
.getMergedAnnotationAttributes(type, FilteredEndpoint.class);
if (attributes == null) {
return null;
}
return attributes.getClass("value");
return MergedAnnotations.from(type).get(FilteredEndpoint.class)
.getValue(MergedAnnotation.VALUE, Class.class).orElse(null);
}
public String getBeanName() {
@@ -498,17 +494,15 @@ public abstract class EndpointDiscoverer<E extends ExposableEndpoint<O>, O exten
ExtensionBean(String beanName, Object bean) {
this.bean = bean;
this.beanName = beanName;
AnnotationAttributes attributes = AnnotatedElementUtils
.getMergedAnnotationAttributes(bean.getClass(),
EndpointExtension.class);
Class<?> endpointType = attributes.getClass("endpoint");
AnnotationAttributes endpointAttributes = AnnotatedElementUtils
.findMergedAnnotationAttributes(endpointType, Endpoint.class, true,
true);
Assert.state(endpointAttributes != null, () -> "Extension "
MergedAnnotation<EndpointExtension> extensionAnnotation = MergedAnnotations
.from(bean.getClass()).get(EndpointExtension.class);
Class<?> endpointType = extensionAnnotation.getClass("endpoint");
MergedAnnotation<Endpoint> endpointAnnotation = MergedAnnotations
.from(endpointType, SearchStrategy.EXHAUSTIVE).get(Endpoint.class);
Assert.state(endpointAnnotation.isPresent(), () -> "Extension "
+ endpointType.getName() + " does not specify an endpoint");
this.endpointId = EndpointId.of(endpointAttributes.getString("id"));
this.filter = attributes.getClass("filter");
this.endpointId = EndpointId.of(endpointAnnotation.getString("id"));
this.filter = extensionAnnotation.getClass("filter");
}
public String getBeanName() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -29,7 +29,7 @@ import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;
import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;
import org.springframework.boot.actuate.endpoint.web.PathMapper;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.util.ClassUtils;
/**
@@ -62,8 +62,9 @@ public class ControllerEndpointDiscoverer
@Override
protected boolean isEndpointExposed(Object endpointBean) {
Class<?> type = ClassUtils.getUserClass(endpointBean.getClass());
return AnnotatedElementUtils.isAnnotated(type, ControllerEndpoint.class)
|| AnnotatedElementUtils.isAnnotated(type, RestControllerEndpoint.class);
MergedAnnotations annotations = MergedAnnotations.from(type);
return annotations.isPresent(ControllerEndpoint.class)
|| annotations.isPresent(RestControllerEndpoint.class);
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -30,7 +30,7 @@ import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
import org.springframework.boot.actuate.endpoint.web.PathMapper;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.util.ClassUtils;
/**
@@ -62,7 +62,7 @@ public class ServletEndpointDiscoverer
@Override
protected boolean isEndpointExposed(Object endpointBean) {
Class<?> type = ClassUtils.getUserClass(endpointBean.getClass());
return AnnotatedElementUtils.isAnnotated(type, ServletEndpoint.class);
return MergedAnnotations.from(type).isPresent(ServletEndpoint.class);
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -31,7 +31,8 @@ import io.micrometer.core.instrument.LongTaskTimer;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotationCollectors;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
@@ -116,7 +117,8 @@ public class LongTaskTimingHandlerInterceptor implements HandlerInterceptor {
}
private Set<Timed> findTimedAnnotations(AnnotatedElement element) {
return AnnotationUtils.getDeclaredRepeatableAnnotations(element, Timed.class);
return MergedAnnotations.from(element).stream(Timed.class)
.collect(MergedAnnotationCollectors.toAnnotationSet());
}
private void stopLongTaskTimers(LongTaskTimingContext timingContext) {

View File

@@ -34,7 +34,8 @@ import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.Timer.Builder;
import io.micrometer.core.instrument.Timer.Sample;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotationCollectors;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.http.HttpStatus;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.method.HandlerMethod;
@@ -141,7 +142,8 @@ public class WebMvcMetricsFilter extends OncePerRequestFilter {
}
private Set<Timed> findTimedAnnotations(AnnotatedElement element) {
return AnnotationUtils.getDeclaredRepeatableAnnotations(element, Timed.class);
return MergedAnnotations.from(element).stream(Timed.class)
.collect(MergedAnnotationCollectors.toAnnotationSet());
}
private void record(TimingContext timingContext, HttpServletResponse response,

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -31,7 +31,8 @@ import org.junit.runners.model.Statement;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.test.web.reactive.server.WebTestClient;
@@ -181,7 +182,8 @@ abstract class AbstractWebEndpointRunner extends BlockJUnit4ClassRunner {
}
private boolean isConfiguration(Class<?> candidate) {
return AnnotationUtils.findAnnotation(candidate, Configuration.class) != null;
return MergedAnnotations.from(candidate, SearchStrategy.EXHAUSTIVE)
.isPresent(Configuration.class);
}
private WebTestClient createWebTestClient() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -42,7 +42,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.StandardMethodMetadata;
import org.springframework.util.Assert;
@@ -117,8 +117,10 @@ final class BeanTypeRegistry implements SmartInitializingSingleton {
public Set<String> getNamesForAnnotation(Class<? extends Annotation> annotation) {
updateTypesIfNecessary();
return this.beanTypes.entrySet().stream()
.filter((entry) -> entry.getValue() != null && AnnotationUtils
.findAnnotation(entry.getValue().resolve(), annotation) != null)
.filter((entry) -> entry.getValue() != null && MergedAnnotations
.from(entry.getValue().resolve(),
MergedAnnotations.SearchStrategy.EXHAUSTIVE)
.isPresent(annotation))
.map(Map.Entry::getKey)
.collect(Collectors.toCollection(LinkedHashSet::new));
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -44,7 +44,7 @@ import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.ConfigurationCondition;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.MethodMetadata;
@@ -531,8 +531,9 @@ class OnBeanCondition extends FilteringSpringBootCondition
}
private boolean isBeanMethod(Method method) {
return method != null
&& AnnotatedElementUtils.hasAnnotation(method, Bean.class);
return method != null && MergedAnnotations
.from(method, MergedAnnotations.SearchStrategy.EXHAUSTIVE)
.isPresent(Bean.class);
}
public TypeExtractor getTypeExtractor(ClassLoader classLoader) {

View File

@@ -20,7 +20,9 @@ import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.boot.autoconfigure.jersey.JerseyProperties;
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.util.StringUtils;
/**
@@ -49,16 +51,11 @@ public class DefaultJerseyApplicationPath implements JerseyApplicationPath {
if (StringUtils.hasLength(this.applicationPath)) {
return this.applicationPath;
}
return findApplicationPath(AnnotationUtils.findAnnotation(
this.config.getApplication().getClass(), ApplicationPath.class));
}
private static String findApplicationPath(ApplicationPath annotation) {
// Jersey doesn't like to be the default servlet, so map to /* as a fallback
if (annotation == null) {
return "/*";
}
return annotation.value();
return MergedAnnotations
.from(this.config.getApplication().getClass(), SearchStrategy.EXHAUSTIVE)
.get(ApplicationPath.class).getValue(MergedAnnotation.VALUE, String.class)
.orElse("/*");
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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,7 +21,8 @@ import java.util.List;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
@@ -39,12 +40,10 @@ class OverrideAutoConfigurationContextCustomizerFactory
@Override
public ContextCustomizer createContextCustomizer(Class<?> testClass,
List<ContextConfigurationAttributes> configurationAttributes) {
OverrideAutoConfiguration annotation = AnnotatedElementUtils
.findMergedAnnotation(testClass, OverrideAutoConfiguration.class);
if (annotation != null && !annotation.enabled()) {
return new DisableAutoConfigurationContextCustomizer();
}
return null;
boolean enabled = MergedAnnotations.from(testClass, SearchStrategy.EXHAUSTIVE)
.get(OverrideAutoConfiguration.class).getValue("enabled", Boolean.class)
.orElse(true);
return !enabled ? new DisableAutoConfigurationContextCustomizer() : null;
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -17,7 +17,8 @@
package org.springframework.boot.test.autoconfigure.data.jdbc;
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.TestContextBootstrapper;
/**
@@ -29,9 +30,9 @@ class DataJdbcTestContextBootstrapper extends SpringBootTestContextBootstrapper
@Override
protected String[] getProperties(Class<?> testClass) {
DataJdbcTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
DataJdbcTest.class);
return (annotation != null) ? annotation.properties() : null;
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(DataJdbcTest.class).getValue("properties", String[].class)
.orElse(null);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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,58 +16,19 @@
package org.springframework.boot.test.autoconfigure.data.jdbc;
import java.util.Collections;
import java.util.Set;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.boot.test.autoconfigure.filter.StandardAnnotationCustomizableTypeExcludeFilter;
/**
* {@link TypeExcludeFilter} for {@link DataJdbcTest @DataJdbcTest}.
*
* @author Andy Wilkinson
*/
class DataJdbcTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
private final DataJdbcTest annotation;
class DataJdbcTypeExcludeFilter
extends StandardAnnotationCustomizableTypeExcludeFilter<DataJdbcTest> {
DataJdbcTypeExcludeFilter(Class<?> testClass) {
this.annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
DataJdbcTest.class);
}
@Override
protected boolean hasAnnotation() {
return this.annotation != null;
}
@Override
protected Filter[] getFilters(FilterType type) {
switch (type) {
case INCLUDE:
return this.annotation.includeFilters();
case EXCLUDE:
return this.annotation.excludeFilters();
default:
throw new IllegalStateException("Unsupported type " + type);
}
}
@Override
protected boolean isUseDefaultFilters() {
return this.annotation.useDefaultFilters();
}
@Override
protected Set<Class<?>> getDefaultIncludes() {
return Collections.emptySet();
}
@Override
protected Set<Class<?>> getComponentIncludes() {
return Collections.emptySet();
super(testClass);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -17,7 +17,8 @@
package org.springframework.boot.test.autoconfigure.data.ldap;
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.TestContextBootstrapper;
/**
@@ -29,9 +30,9 @@ class DataLdapTestContextBootstrapper extends SpringBootTestContextBootstrapper
@Override
protected String[] getProperties(Class<?> testClass) {
DataLdapTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
DataLdapTest.class);
return (annotation != null) ? annotation.properties() : null;
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(DataLdapTest.class).getValue("properties", String[].class)
.orElse(null);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 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,58 +16,19 @@
package org.springframework.boot.test.autoconfigure.data.ldap;
import java.util.Collections;
import java.util.Set;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.boot.test.autoconfigure.filter.StandardAnnotationCustomizableTypeExcludeFilter;
/**
* {@link TypeExcludeFilter} for {@link DataLdapTest @DataLdapTest}.
*
* @author Eddú Meléndez
*/
class DataLdapTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
private final DataLdapTest annotation;
class DataLdapTypeExcludeFilter
extends StandardAnnotationCustomizableTypeExcludeFilter<DataLdapTest> {
DataLdapTypeExcludeFilter(Class<?> testClass) {
this.annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
DataLdapTest.class);
}
@Override
protected boolean hasAnnotation() {
return this.annotation != null;
}
@Override
protected Filter[] getFilters(FilterType type) {
switch (type) {
case INCLUDE:
return this.annotation.includeFilters();
case EXCLUDE:
return this.annotation.excludeFilters();
default:
throw new IllegalStateException("Unsupported type " + type);
}
}
@Override
protected boolean isUseDefaultFilters() {
return this.annotation.useDefaultFilters();
}
@Override
protected Set<Class<?>> getDefaultIncludes() {
return Collections.emptySet();
}
@Override
protected Set<Class<?>> getComponentIncludes() {
return Collections.emptySet();
super(testClass);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -17,7 +17,8 @@
package org.springframework.boot.test.autoconfigure.data.mongo;
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.TestContextBootstrapper;
/**
@@ -29,9 +30,9 @@ class DataMongoTestContextBootstrapper extends SpringBootTestContextBootstrapper
@Override
protected String[] getProperties(Class<?> testClass) {
DataMongoTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
DataMongoTest.class);
return (annotation != null) ? annotation.properties() : null;
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(DataMongoTest.class).getValue("properties", String[].class)
.orElse(null);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 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,58 +16,19 @@
package org.springframework.boot.test.autoconfigure.data.mongo;
import java.util.Collections;
import java.util.Set;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.boot.test.autoconfigure.filter.StandardAnnotationCustomizableTypeExcludeFilter;
/**
* {@link TypeExcludeFilter} for {@link DataMongoTest @DataMongoTest}.
*
* @author Michael Simons
*/
class DataMongoTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
private final DataMongoTest annotation;
class DataMongoTypeExcludeFilter
extends StandardAnnotationCustomizableTypeExcludeFilter<DataMongoTest> {
DataMongoTypeExcludeFilter(Class<?> testClass) {
this.annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
DataMongoTest.class);
}
@Override
protected boolean hasAnnotation() {
return this.annotation != null;
}
@Override
protected Filter[] getFilters(FilterType type) {
switch (type) {
case INCLUDE:
return this.annotation.includeFilters();
case EXCLUDE:
return this.annotation.excludeFilters();
default:
throw new IllegalStateException("Unsupported type " + type);
}
}
@Override
protected boolean isUseDefaultFilters() {
return this.annotation.useDefaultFilters();
}
@Override
protected Set<Class<?>> getDefaultIncludes() {
return Collections.emptySet();
}
@Override
protected Set<Class<?>> getComponentIncludes() {
return Collections.emptySet();
super(testClass);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -17,7 +17,8 @@
package org.springframework.boot.test.autoconfigure.data.neo4j;
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.TestContextBootstrapper;
/**
@@ -29,9 +30,9 @@ class DataNeo4jTestContextBootstrapper extends SpringBootTestContextBootstrapper
@Override
protected String[] getProperties(Class<?> testClass) {
DataNeo4jTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
DataNeo4jTest.class);
return (annotation != null) ? annotation.properties() : null;
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(DataNeo4jTest.class).getValue("properties", String[].class)
.orElse(null);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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,58 +16,19 @@
package org.springframework.boot.test.autoconfigure.data.neo4j;
import java.util.Collections;
import java.util.Set;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.boot.test.autoconfigure.filter.StandardAnnotationCustomizableTypeExcludeFilter;
/**
* {@link TypeExcludeFilter} for {@link DataNeo4jTest @DataNeo4jTest}.
*
* @author Eddú Meléndez
*/
class DataNeo4jTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
private final DataNeo4jTest annotation;
class DataNeo4jTypeExcludeFilter
extends StandardAnnotationCustomizableTypeExcludeFilter<DataNeo4jTest> {
DataNeo4jTypeExcludeFilter(Class<?> testClass) {
this.annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
DataNeo4jTest.class);
}
@Override
protected boolean hasAnnotation() {
return this.annotation != null;
}
@Override
protected Filter[] getFilters(FilterType type) {
switch (type) {
case INCLUDE:
return this.annotation.includeFilters();
case EXCLUDE:
return this.annotation.excludeFilters();
default:
throw new IllegalStateException("Unsupported type " + type);
}
}
@Override
protected boolean isUseDefaultFilters() {
return this.annotation.useDefaultFilters();
}
@Override
protected Set<Class<?>> getDefaultIncludes() {
return Collections.emptySet();
}
@Override
protected Set<Class<?>> getComponentIncludes() {
return Collections.emptySet();
super(testClass);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -17,7 +17,8 @@
package org.springframework.boot.test.autoconfigure.data.redis;
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.TestContextBootstrapper;
/**
@@ -29,9 +30,9 @@ class DataRedisTestContextBootstrapper extends SpringBootTestContextBootstrapper
@Override
protected String[] getProperties(Class<?> testClass) {
DataRedisTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
DataRedisTest.class);
return (annotation != null) ? annotation.properties() : null;
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(DataRedisTest.class).getValue("properties", String[].class)
.orElse(null);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 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,58 +16,19 @@
package org.springframework.boot.test.autoconfigure.data.redis;
import java.util.Collections;
import java.util.Set;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.boot.test.autoconfigure.filter.StandardAnnotationCustomizableTypeExcludeFilter;
/**
* {@link TypeExcludeFilter} for {@link DataRedisTest @DataRedisTest}.
*
* @author Jayaram Pradhan
*/
class DataRedisTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
private final DataRedisTest annotation;
class DataRedisTypeExcludeFilter
extends StandardAnnotationCustomizableTypeExcludeFilter<DataRedisTest> {
DataRedisTypeExcludeFilter(Class<?> testClass) {
this.annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
DataRedisTest.class);
}
@Override
protected boolean hasAnnotation() {
return this.annotation != null;
}
@Override
protected Filter[] getFilters(FilterType type) {
switch (type) {
case INCLUDE:
return this.annotation.includeFilters();
case EXCLUDE:
return this.annotation.excludeFilters();
default:
throw new IllegalStateException("Unsupported type " + type);
}
}
@Override
protected boolean isUseDefaultFilters() {
return this.annotation.useDefaultFilters();
}
@Override
protected Set<Class<?>> getDefaultIncludes() {
return Collections.emptySet();
}
@Override
protected Set<Class<?>> getComponentIncludes() {
return Collections.emptySet();
super(testClass);
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2012-2019 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.test.autoconfigure.filter;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.Set;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
/**
* {@link AnnotationCustomizableTypeExcludeFilter} that can be used to any test annotation
* that uses the standard {code includeFilters}, {code excludeFilters} and
* {@code useDefaultFilters} attributes.
*
* @param <A> the annotation type
* @author Phillip Webb
* @since 2.2.0
*/
public abstract class StandardAnnotationCustomizableTypeExcludeFilter<A extends Annotation>
extends AnnotationCustomizableTypeExcludeFilter {
private static final Filter[] NO_FILTERS = {};
private static final String[] FILTER_TYPE_ATTRIBUTES;
static {
FilterType[] filterValues = FilterType.values();
FILTER_TYPE_ATTRIBUTES = new String[filterValues.length];
for (int i = 0; i < filterValues.length; i++) {
FILTER_TYPE_ATTRIBUTES[i] = filterValues[i].name().toLowerCase() + "Filters";
}
}
private MergedAnnotation<A> annotation;
protected StandardAnnotationCustomizableTypeExcludeFilter(Class<?> testClass) {
this.annotation = MergedAnnotations
.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(getAnnotationType());
}
protected final MergedAnnotation<A> getAnnotation() {
return this.annotation;
}
@Override
protected boolean hasAnnotation() {
return this.annotation.isPresent();
}
@Override
protected Filter[] getFilters(FilterType type) {
return this.annotation
.getValue(FILTER_TYPE_ATTRIBUTES[type.ordinal()], Filter[].class)
.orElse(NO_FILTERS);
}
@Override
protected boolean isUseDefaultFilters() {
return this.annotation.getValue("useDefaultFilters", Boolean.class).orElse(false);
}
@Override
protected Set<Class<?>> getDefaultIncludes() {
return Collections.emptySet();
}
@Override
protected Set<Class<?>> getComponentIncludes() {
return Collections.emptySet();
}
@SuppressWarnings("unchecked")
protected Class<A> getAnnotationType() {
ResolvableType type = ResolvableType.forClass(
StandardAnnotationCustomizableTypeExcludeFilter.class, getClass());
return (Class<A>) type.resolveGeneric();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 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,13 +19,15 @@ package org.springframework.boot.test.autoconfigure.filter;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
import org.springframework.util.ObjectUtils;
/**
* {@link ContextCustomizerFactory} to support
@@ -36,17 +38,26 @@ import org.springframework.test.context.ContextCustomizerFactory;
*/
class TypeExcludeFiltersContextCustomizerFactory implements ContextCustomizerFactory {
private static final Class<?>[] NO_FILTERS = {};
@Override
public ContextCustomizer createContextCustomizer(Class<?> testClass,
List<ContextConfigurationAttributes> configurationAttributes) {
TypeExcludeFilters annotation = AnnotatedElementUtils
.findMergedAnnotation(testClass, TypeExcludeFilters.class);
if (annotation != null) {
Set<Class<? extends TypeExcludeFilter>> filterClasses = new LinkedHashSet<>(
Arrays.asList(annotation.value()));
return new TypeExcludeFiltersContextCustomizer(testClass, filterClasses);
Class<?>[] filterClasses = MergedAnnotations
.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(TypeExcludeFilters.class)
.getValue(MergedAnnotation.VALUE, Class[].class).orElse(NO_FILTERS);
if (ObjectUtils.isEmpty(filterClasses)) {
return null;
}
return null;
return createContextCustomizer(testClass, filterClasses);
}
@SuppressWarnings("unchecked")
private ContextCustomizer createContextCustomizer(Class<?> testClass,
Class<?>[] filterClasses) {
return new TypeExcludeFiltersContextCustomizer(testClass, new LinkedHashSet<>(
Arrays.asList((Class<? extends TypeExcludeFilter>[]) filterClasses)));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -17,7 +17,8 @@
package org.springframework.boot.test.autoconfigure.jdbc;
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.TestContextBootstrapper;
/**
@@ -29,9 +30,8 @@ class JdbcTestContextBootstrapper extends SpringBootTestContextBootstrapper {
@Override
protected String[] getProperties(Class<?> testClass) {
JdbcTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
JdbcTest.class);
return (annotation != null) ? annotation.properties() : null;
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(JdbcTest.class).getValue("properties", String[].class).orElse(null);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 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,57 +16,19 @@
package org.springframework.boot.test.autoconfigure.jdbc;
import java.util.Collections;
import java.util.Set;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.boot.test.autoconfigure.filter.StandardAnnotationCustomizableTypeExcludeFilter;
/**
* {@link TypeExcludeFilter} for {@link JdbcTest @JdbcTest}.
*
* @author Stephane Nicoll
*/
class JdbcTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
private final JdbcTest annotation;
class JdbcTypeExcludeFilter
extends StandardAnnotationCustomizableTypeExcludeFilter<JdbcTest> {
JdbcTypeExcludeFilter(Class<?> testClass) {
this.annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
JdbcTest.class);
}
@Override
protected boolean hasAnnotation() {
return this.annotation != null;
}
@Override
protected ComponentScan.Filter[] getFilters(FilterType type) {
switch (type) {
case INCLUDE:
return this.annotation.includeFilters();
case EXCLUDE:
return this.annotation.excludeFilters();
}
throw new IllegalStateException("Unsupported type " + type);
}
@Override
protected boolean isUseDefaultFilters() {
return this.annotation.useDefaultFilters();
}
@Override
protected Set<Class<?>> getDefaultIncludes() {
return Collections.emptySet();
}
@Override
protected Set<Class<?>> getComponentIncludes() {
return Collections.emptySet();
super(testClass);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -17,7 +17,8 @@
package org.springframework.boot.test.autoconfigure.jooq;
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.TestContextBootstrapper;
/**
@@ -29,9 +30,8 @@ class JooqTestContextBootstrapper extends SpringBootTestContextBootstrapper {
@Override
protected String[] getProperties(Class<?> testClass) {
JooqTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
JooqTest.class);
return (annotation != null) ? annotation.properties() : null;
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(JooqTest.class).getValue("properties", String[].class).orElse(null);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 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,58 +16,19 @@
package org.springframework.boot.test.autoconfigure.jooq;
import java.util.Collections;
import java.util.Set;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.boot.test.autoconfigure.filter.StandardAnnotationCustomizableTypeExcludeFilter;
/**
* {@link TypeExcludeFilter} for {@link JooqTest @JooqTest}.
*
* @author Michael Simons
*/
class JooqTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
private final JooqTest annotation;
class JooqTypeExcludeFilter
extends StandardAnnotationCustomizableTypeExcludeFilter<JooqTest> {
JooqTypeExcludeFilter(Class<?> testClass) {
this.annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
JooqTest.class);
}
@Override
protected boolean hasAnnotation() {
return this.annotation != null;
}
@Override
protected Filter[] getFilters(FilterType type) {
switch (type) {
case INCLUDE:
return this.annotation.includeFilters();
case EXCLUDE:
return this.annotation.excludeFilters();
default:
throw new IllegalStateException("Unsupported type " + type);
}
}
@Override
protected boolean isUseDefaultFilters() {
return this.annotation.useDefaultFilters();
}
@Override
protected Set<Class<?>> getDefaultIncludes() {
return Collections.emptySet();
}
@Override
protected Set<Class<?>> getComponentIncludes() {
return Collections.emptySet();
super(testClass);
}
}

View File

@@ -22,9 +22,7 @@ import java.util.Set;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.jackson.JsonComponent;
import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.boot.test.autoconfigure.filter.StandardAnnotationCustomizableTypeExcludeFilter;
import org.springframework.util.ClassUtils;
/**
@@ -32,7 +30,8 @@ import org.springframework.util.ClassUtils;
*
* @author Phillip Webb
*/
class JsonExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
class JsonExcludeFilter
extends StandardAnnotationCustomizableTypeExcludeFilter<JsonTest> {
private static final String JACKSON_MODULE = "com.fasterxml.jackson.databind.Module";
@@ -49,32 +48,8 @@ class JsonExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
DEFAULT_INCLUDES = Collections.unmodifiableSet(includes);
}
private final JsonTest annotation;
JsonExcludeFilter(Class<?> testClass) {
this.annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
JsonTest.class);
}
@Override
protected boolean hasAnnotation() {
return this.annotation != null;
}
@Override
protected Filter[] getFilters(FilterType type) {
switch (type) {
case INCLUDE:
return this.annotation.includeFilters();
case EXCLUDE:
return this.annotation.excludeFilters();
}
throw new IllegalStateException("Unsupported type " + type);
}
@Override
protected boolean isUseDefaultFilters() {
return this.annotation.useDefaultFilters();
super(testClass);
}
@Override
@@ -82,9 +57,4 @@ class JsonExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
return DEFAULT_INCLUDES;
}
@Override
protected Set<Class<?>> getComponentIncludes() {
return Collections.emptySet();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -17,7 +17,8 @@
package org.springframework.boot.test.autoconfigure.json;
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.TestContextBootstrapper;
/**
@@ -29,9 +30,8 @@ class JsonTestContextBootstrapper extends SpringBootTestContextBootstrapper {
@Override
protected String[] getProperties(Class<?> testClass) {
JsonTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
JsonTest.class);
return (annotation != null) ? annotation.properties() : null;
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(JsonTest.class).getValue("properties", String[].class).orElse(null);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -17,7 +17,8 @@
package org.springframework.boot.test.autoconfigure.orm.jpa;
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.TestContextBootstrapper;
/**
@@ -29,9 +30,9 @@ class DataJpaTestContextBootstrapper extends SpringBootTestContextBootstrapper {
@Override
protected String[] getProperties(Class<?> testClass) {
DataJpaTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
DataJpaTest.class);
return (annotation != null) ? annotation.properties() : null;
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(DataJpaTest.class).getValue("properties", String[].class)
.orElse(null);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 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,57 +16,19 @@
package org.springframework.boot.test.autoconfigure.orm.jpa;
import java.util.Collections;
import java.util.Set;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.boot.test.autoconfigure.filter.StandardAnnotationCustomizableTypeExcludeFilter;
/**
* {@link TypeExcludeFilter} for {@link DataJpaTest @DataJpaTest}.
*
* @author Phillip Webb
*/
class DataJpaTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
private final DataJpaTest annotation;
class DataJpaTypeExcludeFilter
extends StandardAnnotationCustomizableTypeExcludeFilter<DataJpaTest> {
DataJpaTypeExcludeFilter(Class<?> testClass) {
this.annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
DataJpaTest.class);
}
@Override
protected boolean hasAnnotation() {
return this.annotation != null;
}
@Override
protected Filter[] getFilters(FilterType type) {
switch (type) {
case INCLUDE:
return this.annotation.includeFilters();
case EXCLUDE:
return this.annotation.excludeFilters();
}
throw new IllegalStateException("Unsupported type " + type);
}
@Override
protected boolean isUseDefaultFilters() {
return this.annotation.useDefaultFilters();
}
@Override
protected Set<Class<?>> getDefaultIncludes() {
return Collections.emptySet();
}
@Override
protected Set<Class<?>> getComponentIncludes() {
return Collections.emptySet();
super(testClass);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.boot.test.autoconfigure.properties;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotationPredicates;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
@@ -61,93 +58,53 @@ public class AnnotationsPropertySource extends EnumerablePropertySource<Class<?>
private Map<String, Object> getProperties(Class<?> source) {
Map<String, Object> properties = new LinkedHashMap<>();
collectProperties(source, source, properties, new HashSet<>());
return Collections.unmodifiableMap(properties);
}
private void collectProperties(Class<?> root, Class<?> source,
Map<String, Object> properties, Set<Class<?>> seen) {
if (source != null && seen.add(source)) {
for (Annotation annotation : getMergedAnnotations(root, source)) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
PropertyMapping typeMapping = annotation.annotationType()
.getAnnotation(PropertyMapping.class);
for (Method attribute : annotation.annotationType()
.getDeclaredMethods()) {
collectProperties(annotation, attribute, typeMapping, properties);
MergedAnnotations.from(source, SearchStrategy.SUPERCLASS).stream()
.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getType))
.forEach((annotation) -> {
Class<Annotation> type = annotation.getType();
MergedAnnotation<?> typeMapping = MergedAnnotations.from(type).get(
PropertyMapping.class, MergedAnnotation::isDirectlyPresent);
String prefix = typeMapping
.getValue(MergedAnnotation.VALUE, String.class).orElse("");
SkipPropertyMapping defaultSkip = typeMapping
.getValue("skip", SkipPropertyMapping.class)
.orElse(SkipPropertyMapping.YES);
for (Method attribute : type.getDeclaredMethods()) {
collectProperties(prefix, defaultSkip, annotation, attribute,
properties);
}
collectProperties(root, annotation.annotationType(), properties,
seen);
}
}
collectProperties(root, source.getSuperclass(), properties, seen);
}
});
return properties;
}
private List<Annotation> getMergedAnnotations(Class<?> root, Class<?> source) {
List<Annotation> mergedAnnotations = new ArrayList<>();
Annotation[] annotations = AnnotationUtils.getAnnotations(source);
if (annotations != null) {
for (Annotation annotation : annotations) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
Annotation mergedAnnotation = findMergedAnnotation(root,
annotation.annotationType());
if (mergedAnnotation != null) {
mergedAnnotations.add(mergedAnnotation);
}
}
}
}
return mergedAnnotations;
}
private Annotation findMergedAnnotation(Class<?> source,
Class<? extends Annotation> annotationType) {
if (source == null) {
return null;
}
Annotation mergedAnnotation = AnnotatedElementUtils.getMergedAnnotation(source,
annotationType);
return (mergedAnnotation != null) ? mergedAnnotation
: findMergedAnnotation(source.getSuperclass(), annotationType);
}
private void collectProperties(Annotation annotation, Method attribute,
PropertyMapping typeMapping, Map<String, Object> properties) {
PropertyMapping attributeMapping = AnnotationUtils.getAnnotation(attribute,
PropertyMapping.class);
SkipPropertyMapping skip = getMappingType(typeMapping, attributeMapping);
private void collectProperties(String prefix, SkipPropertyMapping defaultSkip,
MergedAnnotation<?> annotation, Method attribute,
Map<String, Object> properties) {
MergedAnnotation<?> attributeMapping = MergedAnnotations.from(attribute)
.get(PropertyMapping.class);
SkipPropertyMapping skip = attributeMapping
.getValue("skip", SkipPropertyMapping.class).orElse(defaultSkip);
if (skip == SkipPropertyMapping.YES) {
return;
}
ReflectionUtils.makeAccessible(attribute);
Object value = ReflectionUtils.invokeMethod(attribute, annotation);
Optional<Object> value = annotation.getValue(attribute.getName());
if (!value.isPresent()) {
return;
}
if (skip == SkipPropertyMapping.ON_DEFAULT_VALUE) {
Object defaultValue = AnnotationUtils.getDefaultValue(annotation,
attribute.getName());
if (ObjectUtils.nullSafeEquals(value, defaultValue)) {
if (ObjectUtils.nullSafeEquals(value.get(),
annotation.getDefaultValue(attribute.getName()).orElse(null))) {
return;
}
}
String name = getName(typeMapping, attributeMapping, attribute);
putProperties(name, value, properties);
String name = getName(prefix, attributeMapping, attribute);
putProperties(name, value.get(), properties);
}
private SkipPropertyMapping getMappingType(PropertyMapping typeMapping,
PropertyMapping attributeMapping) {
if (attributeMapping != null) {
return attributeMapping.skip();
}
if (typeMapping != null) {
return typeMapping.skip();
}
return SkipPropertyMapping.YES;
}
private String getName(PropertyMapping typeMapping, PropertyMapping attributeMapping,
private String getName(String prefix, MergedAnnotation<?> attributeMapping,
Method attribute) {
String prefix = (typeMapping != null) ? typeMapping.value() : "";
String name = (attributeMapping != null) ? attributeMapping.value() : "";
String name = attributeMapping.getValue(MergedAnnotation.VALUE, String.class)
.orElse("");
if (!StringUtils.hasText(name)) {
name = toKebabCase(attribute.getName());
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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,14 +16,15 @@
package org.springframework.boot.test.autoconfigure.properties;
import java.lang.annotation.Annotation;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ConfigurableApplicationContext;
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.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextCustomizer;
@@ -76,22 +77,12 @@ class PropertyMappingContextCustomizer implements ContextCustomizer {
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
Class<?> beanClass = bean.getClass();
Set<Class<?>> components = new LinkedHashSet<>();
Set<Class<?>> propertyMappings = new LinkedHashSet<>();
while (beanClass != null) {
Annotation[] annotations = AnnotationUtils.getAnnotations(beanClass);
if (annotations != null) {
for (Annotation annotation : annotations) {
if (isAnnotated(annotation, Component.class)) {
components.add(annotation.annotationType());
}
if (isAnnotated(annotation, PropertyMapping.class)) {
propertyMappings.add(annotation.annotationType());
}
}
}
beanClass = beanClass.getSuperclass();
}
MergedAnnotations annotations = MergedAnnotations.from(beanClass,
SearchStrategy.SUPERCLASS);
Set<Class<?>> components = annotations.stream(Component.class)
.map(this::getRoot).collect(Collectors.toSet());
Set<Class<?>> propertyMappings = annotations.stream(PropertyMapping.class)
.map(this::getRoot).collect(Collectors.toSet());
if (!components.isEmpty() && !propertyMappings.isEmpty()) {
throw new IllegalStateException("The @PropertyMapping "
+ getAnnotationsDescription(propertyMappings)
@@ -101,15 +92,11 @@ class PropertyMappingContextCustomizer implements ContextCustomizer {
return bean;
}
private boolean isAnnotated(Annotation element,
Class<? extends Annotation> annotationType) {
try {
return element.annotationType().equals(annotationType) || AnnotationUtils
.findAnnotation(element.annotationType(), annotationType) != null;
}
catch (Throwable ex) {
return false;
private Class<?> getRoot(MergedAnnotation<?> annotation) {
while (annotation.getParent() != null) {
annotation = annotation.getParent();
}
return annotation.getType();
}
private String getAnnotationsDescription(Set<Class<?>> annotations) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -23,9 +23,7 @@ import java.util.Set;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.jackson.JsonComponent;
import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.boot.test.autoconfigure.filter.StandardAnnotationCustomizableTypeExcludeFilter;
import org.springframework.util.ClassUtils;
/**
@@ -33,7 +31,10 @@ import org.springframework.util.ClassUtils;
*
* @author Stephane Nicoll
*/
class RestClientExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
class RestClientExcludeFilter
extends StandardAnnotationCustomizableTypeExcludeFilter<RestClientTest> {
private static final Class<?>[] NO_COMPONENTS = {};
private static final String DATABIND_MODULE_CLASS_NAME = "com.fasterxml.jackson.databind.Module";
@@ -56,32 +57,12 @@ class RestClientExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
DEFAULT_INCLUDES = Collections.unmodifiableSet(includes);
}
private final RestClientTest annotation;
private final Class<?>[] components;
RestClientExcludeFilter(Class<?> testClass) {
this.annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
RestClientTest.class);
}
@Override
protected boolean hasAnnotation() {
return this.annotation != null;
}
@Override
protected Filter[] getFilters(FilterType type) {
switch (type) {
case INCLUDE:
return this.annotation.includeFilters();
case EXCLUDE:
return this.annotation.excludeFilters();
}
throw new IllegalStateException("Unsupported type " + type);
}
@Override
protected boolean isUseDefaultFilters() {
return this.annotation.useDefaultFilters();
super(testClass);
this.components = getAnnotation().getValue("components", Class[].class)
.orElse(NO_COMPONENTS);
}
@Override
@@ -91,7 +72,7 @@ class RestClientExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
@Override
protected Set<Class<?>> getComponentIncludes() {
return new LinkedHashSet<>(Arrays.asList(this.annotation.components()));
return new LinkedHashSet<>(Arrays.asList(this.components));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -17,7 +17,8 @@
package org.springframework.boot.test.autoconfigure.web.client;
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.TestContextBootstrapper;
/**
@@ -29,9 +30,9 @@ class RestClientTestContextBootstrapper extends SpringBootTestContextBootstrappe
@Override
protected String[] getProperties(Class<?> testClass) {
RestClientTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
RestClientTest.class);
return (annotation != null) ? annotation.properties() : null;
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(RestClientTest.class).getValue("properties", String[].class)
.orElse(null);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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,7 +18,8 @@ package org.springframework.boot.test.autoconfigure.web.reactive;
import org.springframework.boot.test.context.ReactiveWebMergedContextConfiguration;
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.TestContextBootstrapper;
@@ -39,9 +40,9 @@ class WebFluxTestContextBootstrapper extends SpringBootTestContextBootstrapper {
@Override
protected String[] getProperties(Class<?> testClass) {
WebFluxTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
WebFluxTest.class);
return (annotation != null) ? annotation.properties() : null;
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(WebFluxTest.class).getValue("properties", String[].class)
.orElse(null);
}
}

View File

@@ -23,9 +23,7 @@ import java.util.Set;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.jackson.JsonComponent;
import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.boot.test.autoconfigure.filter.StandardAnnotationCustomizableTypeExcludeFilter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.stereotype.Controller;
@@ -39,7 +37,10 @@ import org.springframework.web.server.WebExceptionHandler;
*
* @author Stephane Nicoll
*/
class WebFluxTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
class WebFluxTypeExcludeFilter
extends StandardAnnotationCustomizableTypeExcludeFilter<WebFluxTest> {
private static final Class<?>[] NO_CONTROLLERS = {};
private static final Set<Class<?>> DEFAULT_INCLUDES;
@@ -62,37 +63,17 @@ class WebFluxTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
DEFAULT_INCLUDES_AND_CONTROLLER = Collections.unmodifiableSet(includes);
}
private final WebFluxTest annotation;
private final Class<?>[] controllers;
WebFluxTypeExcludeFilter(Class<?> testClass) {
this.annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
WebFluxTest.class);
}
@Override
protected boolean hasAnnotation() {
return this.annotation != null;
}
@Override
protected ComponentScan.Filter[] getFilters(FilterType type) {
switch (type) {
case INCLUDE:
return this.annotation.includeFilters();
case EXCLUDE:
return this.annotation.excludeFilters();
}
throw new IllegalStateException("Unsupported type " + type);
}
@Override
protected boolean isUseDefaultFilters() {
return this.annotation.useDefaultFilters();
super(testClass);
this.controllers = getAnnotation().getValue("controllers", Class[].class)
.orElse(NO_CONTROLLERS);
}
@Override
protected Set<Class<?>> getDefaultIncludes() {
if (ObjectUtils.isEmpty(this.annotation.controllers())) {
if (ObjectUtils.isEmpty(this.controllers)) {
return DEFAULT_INCLUDES_AND_CONTROLLER;
}
return DEFAULT_INCLUDES;
@@ -100,7 +81,7 @@ class WebFluxTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
@Override
protected Set<Class<?>> getComponentIncludes() {
return new LinkedHashSet<>(Arrays.asList(this.annotation.controllers()));
return new LinkedHashSet<>(Arrays.asList(this.controllers));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -17,7 +17,8 @@
package org.springframework.boot.test.autoconfigure.web.servlet;
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.TestContextBootstrapper;
import org.springframework.test.context.web.WebMergedContextConfiguration;
@@ -39,9 +40,9 @@ class WebMvcTestContextBootstrapper extends SpringBootTestContextBootstrapper {
@Override
protected String[] getProperties(Class<?> testClass) {
WebMvcTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
WebMvcTest.class);
return (annotation != null) ? annotation.properties() : null;
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(WebMvcTest.class).getValue("properties", String[].class)
.orElse(null);
}
}

View File

@@ -23,12 +23,10 @@ import java.util.Set;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.jackson.JsonComponent;
import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter;
import org.springframework.boot.test.autoconfigure.filter.StandardAnnotationCustomizableTypeExcludeFilter;
import org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.http.converter.HttpMessageConverter;
@@ -45,7 +43,10 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
* @author Phillip Webb
* @author Madhura Bhave
*/
class WebMvcTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
class WebMvcTypeExcludeFilter
extends StandardAnnotationCustomizableTypeExcludeFilter<WebMvcTest> {
private static final Class<?>[] NO_CONTROLLERS = {};
private static final String[] OPTIONAL_INCLUDES = {
"org.springframework.security.config.annotation.web.WebSecurityConfigurer" };
@@ -84,37 +85,17 @@ class WebMvcTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
DEFAULT_INCLUDES_AND_CONTROLLER = Collections.unmodifiableSet(includes);
}
private final WebMvcTest annotation;
private final Class<?>[] controllers;
WebMvcTypeExcludeFilter(Class<?> testClass) {
this.annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
WebMvcTest.class);
}
@Override
protected boolean hasAnnotation() {
return this.annotation != null;
}
@Override
protected Filter[] getFilters(FilterType type) {
switch (type) {
case INCLUDE:
return this.annotation.includeFilters();
case EXCLUDE:
return this.annotation.excludeFilters();
}
throw new IllegalStateException("Unsupported type " + type);
}
@Override
protected boolean isUseDefaultFilters() {
return this.annotation.useDefaultFilters();
super(testClass);
this.controllers = getAnnotation().getValue("controllers", Class[].class)
.orElse(NO_CONTROLLERS);
}
@Override
protected Set<Class<?>> getDefaultIncludes() {
if (ObjectUtils.isEmpty(this.annotation.controllers())) {
if (ObjectUtils.isEmpty(this.controllers)) {
return DEFAULT_INCLUDES_AND_CONTROLLER;
}
return DEFAULT_INCLUDES;
@@ -122,7 +103,7 @@ class WebMvcTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
@Override
protected Set<Class<?>> getComponentIncludes() {
return new LinkedHashSet<>(Arrays.asList(this.annotation.controllers()));
return new LinkedHashSet<>(Arrays.asList(this.controllers));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 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,7 +21,8 @@ import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
@@ -40,7 +41,8 @@ class ImportsContextCustomizerFactory implements ContextCustomizerFactory {
@Override
public ContextCustomizer createContextCustomizer(Class<?> testClass,
List<ContextConfigurationAttributes> configAttributes) {
if (AnnotatedElementUtils.findMergedAnnotation(testClass, Import.class) != null) {
if (MergedAnnotations.from(testClass, SearchStrategy.EXHAUSTIVE)
.isPresent(Import.class)) {
assertHasNoBeanMethods(testClass);
return new ImportsContextCustomizer(testClass);
}
@@ -52,7 +54,7 @@ class ImportsContextCustomizerFactory implements ContextCustomizerFactory {
}
private void assertHasNoBeanMethods(Method method) {
Assert.state(!AnnotatedElementUtils.isAnnotated(method, Bean.class),
Assert.state(!MergedAnnotations.from(method).isPresent(Bean.class),
"Test classes cannot include @Bean methods");
}

View File

@@ -27,6 +27,7 @@ import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.mock.web.SpringBootMockServletContext;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.web.reactive.context.GenericReactiveWebApplicationContext;
@@ -36,7 +37,8 @@ import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.SpringVersion;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.StandardEnvironment;
@@ -155,9 +157,9 @@ public class SpringBootContextLoader extends AbstractContextLoader {
* @see SpringApplication#run(String...)
*/
protected String[] getArgs(MergedContextConfiguration config) {
SpringBootTest annotation = AnnotatedElementUtils
.findMergedAnnotation(config.getTestClass(), SpringBootTest.class);
return (annotation != null) ? annotation.args() : NO_ARGS;
return MergedAnnotations.from(config.getTestClass(), SearchStrategy.EXHAUSTIVE)
.get(SpringBootTest.class).getValue("args", String[].class)
.orElse(NO_ARGS);
}
private void setActiveProfiles(ConfigurableEnvironment environment,
@@ -225,12 +227,10 @@ public class SpringBootContextLoader extends AbstractContextLoader {
}
private boolean isEmbeddedWebEnvironment(MergedContextConfiguration config) {
SpringBootTest annotation = AnnotatedElementUtils
.findMergedAnnotation(config.getTestClass(), SpringBootTest.class);
if (annotation != null && annotation.webEnvironment().isEmbedded()) {
return true;
}
return false;
return MergedAnnotations.from(config.getTestClass(), SearchStrategy.EXHAUSTIVE)
.get(SpringBootTest.class)
.getValue("webEnvironment", WebEnvironment.class)
.orElse(WebEnvironment.NONE).isEmbedded();
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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,6 @@
package org.springframework.boot.test.context;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -33,8 +32,10 @@ import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.core.annotation.AnnotatedElementUtils;
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.core.env.Environment;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.test.context.ContextConfiguration;
@@ -163,11 +164,11 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
if (webApplicationType == WebApplicationType.SERVLET
&& (webEnvironment.isEmbedded()
|| webEnvironment == WebEnvironment.MOCK)) {
WebAppConfiguration webAppConfiguration = AnnotatedElementUtils
.findMergedAnnotation(mergedConfig.getTestClass(),
WebAppConfiguration.class);
String resourceBasePath = (webAppConfiguration != null)
? webAppConfiguration.value() : "src/main/webapp";
String resourceBasePath = MergedAnnotations
.from(mergedConfig.getTestClass(), SearchStrategy.EXHAUSTIVE)
.get(WebAppConfiguration.class)
.getValue(MergedAnnotation.VALUE, String.class)
.orElse("src/main/webapp");
mergedConfig = new WebMergedContextConfiguration(mergedConfig,
resourceBasePath);
}
@@ -251,7 +252,8 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
private boolean containsNonTestComponent(Class<?>[] classes) {
for (Class<?> candidate : classes) {
if (!AnnotatedElementUtils.isAnnotated(candidate, TestConfiguration.class)) {
if (!MergedAnnotations.from(candidate, SearchStrategy.INHERITED_ANNOTATIONS)
.isPresent(TestConfiguration.class)) {
return true;
}
}
@@ -330,15 +332,16 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
}
protected SpringBootTest getAnnotation(Class<?> testClass) {
return AnnotatedElementUtils.getMergedAnnotation(testClass, SpringBootTest.class);
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(SpringBootTest.class).synthesize(MergedAnnotation::isPresent)
.orElse(null);
}
protected void verifyConfiguration(Class<?> testClass) {
SpringBootTest springBootTest = getAnnotation(testClass);
if (springBootTest != null
&& (springBootTest.webEnvironment() == WebEnvironment.DEFINED_PORT
|| springBootTest.webEnvironment() == WebEnvironment.RANDOM_PORT)
&& getAnnotation(WebAppConfiguration.class, testClass) != null) {
if (springBootTest != null && isListeningOnPort(springBootTest.webEnvironment())
&& MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.isPresent(WebAppConfiguration.class)) {
throw new IllegalStateException("@WebAppConfiguration should only be used "
+ "with @SpringBootTest when @SpringBootTest is configured with a "
+ "mock web environment. Please remove @WebAppConfiguration or "
@@ -346,9 +349,9 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
}
}
private <T extends Annotation> T getAnnotation(Class<T> annotationType,
Class<?> testClass) {
return AnnotatedElementUtils.getMergedAnnotation(testClass, annotationType);
private boolean isListeningOnPort(WebEnvironment webEnvironment) {
return webEnvironment == WebEnvironment.DEFINED_PORT
|| webEnvironment == WebEnvironment.RANDOM_PORT;
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -26,7 +26,9 @@ import java.util.Map;
import java.util.Set;
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.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
@@ -63,14 +65,12 @@ class DefinitionsParser {
}
private void parseElement(AnnotatedElement element) {
for (MockBean annotation : AnnotationUtils.getRepeatableAnnotations(element,
MockBean.class, MockBeans.class)) {
parseMockBeanAnnotation(annotation, element);
}
for (SpyBean annotation : AnnotationUtils.getRepeatableAnnotations(element,
SpyBean.class, SpyBeans.class)) {
parseSpyBeanAnnotation(annotation, element);
}
MergedAnnotations annotations = MergedAnnotations.from(element,
SearchStrategy.SUPERCLASS);
annotations.stream(MockBean.class).map(MergedAnnotation::synthesize)
.forEach((annotation) -> parseMockBeanAnnotation(annotation, element));
annotations.stream(SpyBean.class).map(MergedAnnotation::synthesize)
.forEach((annotation) -> parseSpyBeanAnnotation(annotation, element));
}
private void parseMockBeanAnnotation(MockBean annotation, AnnotatedElement element) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -26,7 +26,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotations;
/**
* Definition of a Spring {@link Qualifier @Qualifier}.
@@ -93,18 +93,20 @@ class QualifierDefinition {
Annotation[] candidates = field.getDeclaredAnnotations();
Set<Annotation> annotations = new HashSet<>(candidates.length);
for (Annotation candidate : candidates) {
if (!isMockOrSpyAnnotation(candidate)) {
if (!isMockOrSpyAnnotation(candidate.annotationType())) {
annotations.add(candidate);
}
}
return annotations;
}
private static boolean isMockOrSpyAnnotation(Annotation candidate) {
Class<? extends Annotation> type = candidate.annotationType();
return (type.equals(MockBean.class) || type.equals(SpyBean.class)
|| AnnotationUtils.isAnnotationMetaPresent(type, MockBean.class)
|| AnnotationUtils.isAnnotationMetaPresent(type, SpyBean.class));
private static boolean isMockOrSpyAnnotation(Class<? extends Annotation> type) {
if (type.equals(MockBean.class) || type.equals(SpyBean.class)) {
return true;
}
MergedAnnotations metaAnnotations = MergedAnnotations.from(type);
return metaAnnotations.isPresent(MockBean.class)
|| metaAnnotations.isPresent(SpyBean.class);
}
}

View File

@@ -29,6 +29,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate.HttpClientOption;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory;
@@ -37,7 +38,9 @@ import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.MergedContextConfiguration;
@@ -52,9 +55,11 @@ class TestRestTemplateContextCustomizer implements ContextCustomizer {
@Override
public void customizeContext(ConfigurableApplicationContext context,
MergedContextConfiguration mergedContextConfiguration) {
SpringBootTest annotation = AnnotatedElementUtils.getMergedAnnotation(
mergedContextConfiguration.getTestClass(), SpringBootTest.class);
if (annotation.webEnvironment().isEmbedded()) {
MergedAnnotation<?> annotation = MergedAnnotations
.from(mergedContextConfiguration.getTestClass(),
SearchStrategy.INHERITED_ANNOTATIONS)
.get(SpringBootTest.class);
if (annotation.getEnum("webEnvironment", WebEnvironment.class).isEmbedded()) {
registerTestRestTemplate(context);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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,8 @@ package org.springframework.boot.test.web.client;
import java.util.List;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
@@ -35,8 +36,9 @@ class TestRestTemplateContextCustomizerFactory implements ContextCustomizerFacto
@Override
public ContextCustomizer createContextCustomizer(Class<?> testClass,
List<ContextConfigurationAttributes> configAttributes) {
if (AnnotatedElementUtils.findMergedAnnotation(testClass,
SpringBootTest.class) != null) {
MergedAnnotations annotations = MergedAnnotations.from(testClass,
SearchStrategy.INHERITED_ANNOTATIONS);
if (annotations.isPresent(SpringBootTest.class)) {
return new TestRestTemplateContextCustomizer();
}
return null;

View File

@@ -31,6 +31,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.codec.CodecCustomizer;
import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory;
import org.springframework.context.ApplicationContext;
@@ -38,7 +39,9 @@ import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.web.reactive.server.WebTestClient;
@@ -55,9 +58,10 @@ class WebTestClientContextCustomizer implements ContextCustomizer {
@Override
public void customizeContext(ConfigurableApplicationContext context,
MergedContextConfiguration mergedConfig) {
SpringBootTest annotation = AnnotatedElementUtils
.getMergedAnnotation(mergedConfig.getTestClass(), SpringBootTest.class);
if (annotation.webEnvironment().isEmbedded()) {
MergedAnnotation<?> annotation = MergedAnnotations
.from(mergedConfig.getTestClass(), SearchStrategy.INHERITED_ANNOTATIONS)
.get(SpringBootTest.class);
if (annotation.getEnum("webEnvironment", WebEnvironment.class).isEmbedded()) {
registerWebTestClient(context);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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,8 @@ package org.springframework.boot.test.web.reactive.server;
import java.util.List;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
@@ -37,8 +38,9 @@ class WebTestClientContextCustomizerFactory implements ContextCustomizerFactory
@Override
public ContextCustomizer createContextCustomizer(Class<?> testClass,
List<ContextConfigurationAttributes> configAttributes) {
if (isWebClientPresent() && AnnotatedElementUtils.findMergedAnnotation(testClass,
SpringBootTest.class) != null) {
MergedAnnotations annotations = MergedAnnotations.from(testClass,
SearchStrategy.INHERITED_ANNOTATIONS);
if (isWebClientPresent() && annotations.isPresent(SpringBootTest.class)) {
return new WebTestClientContextCustomizer();
}
return null;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -52,7 +52,9 @@ import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.TestClass;
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.util.AntPathMatcher;
import org.springframework.util.StringUtils;
@@ -178,9 +180,14 @@ public class ModifiedClassPathRunner extends BlockJUnit4ClassRunner {
}
private URL[] processUrls(URL[] urls, Class<?> testClass) throws Exception {
ClassPathEntryFilter filter = new ClassPathEntryFilter(testClass);
MergedAnnotations annotations = MergedAnnotations.from(testClass,
SearchStrategy.EXHAUSTIVE);
ClassPathEntryFilter filter = new ClassPathEntryFilter(
annotations.get(ClassPathExclusions.class));
List<URL> processedUrls = new ArrayList<>();
processedUrls.addAll(getAdditionalUrls(testClass));
List<URL> additionalUrls = getAdditionalUrls(
annotations.get(ClassPathOverrides.class));
processedUrls.addAll(additionalUrls);
for (URL url : urls) {
if (!filter.isExcluded(url)) {
processedUrls.add(url);
@@ -189,13 +196,12 @@ public class ModifiedClassPathRunner extends BlockJUnit4ClassRunner {
return processedUrls.toArray(new URL[0]);
}
private List<URL> getAdditionalUrls(Class<?> testClass) throws Exception {
ClassPathOverrides overrides = AnnotationUtils.findAnnotation(testClass,
ClassPathOverrides.class);
if (overrides == null) {
private List<URL> getAdditionalUrls(MergedAnnotation<ClassPathOverrides> annotation)
throws Exception {
if (!annotation.isPresent()) {
return Collections.emptyList();
}
return resolveCoordinates(overrides.value());
return resolveCoordinates(annotation.getStringArray(MergedAnnotation.VALUE));
}
private List<URL> resolveCoordinates(String[] coordinates) throws Exception {
@@ -243,13 +249,13 @@ public class ModifiedClassPathRunner extends BlockJUnit4ClassRunner {
private final AntPathMatcher matcher = new AntPathMatcher();
private ClassPathEntryFilter(Class<?> testClass) throws Exception {
private ClassPathEntryFilter(MergedAnnotation<ClassPathExclusions> annotation)
throws Exception {
this.exclusions = new ArrayList<>();
this.exclusions.add("log4j-*.jar");
ClassPathExclusions exclusions = AnnotationUtils.findAnnotation(testClass,
ClassPathExclusions.class);
if (exclusions != null) {
this.exclusions.addAll(Arrays.asList(exclusions.value()));
if (annotation.isPresent()) {
this.exclusions.addAll(
Arrays.asList(annotation.getStringArray(MergedAnnotation.VALUE)));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -31,7 +31,8 @@ import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
@@ -282,7 +283,8 @@ class BeanDefinitionLoader {
private boolean isComponent(Class<?> type) {
// This has to be a bit of a guess. The only way to be sure that this type is
// eligible is to make a bean definition out of it and try to instantiate it.
if (AnnotationUtils.findAnnotation(type, Component.class) != null) {
if (MergedAnnotations.from(type, SearchStrategy.EXHAUSTIVE)
.isPresent(Component.class)) {
return true;
}
// Nested anonymous classes are not eligible for registration, nor are groovy

View File

@@ -46,6 +46,7 @@ final class ConfigurationPropertiesBeanDefinition extends GenericBeanDefinition
private static <T> Supplier<T> createBean(ConfigurableListableBeanFactory beanFactory,
String beanName, Class<T> type) {
return () -> {
// FIXME review
ConfigurationProperties annotation = getAnnotation(type,
ConfigurationProperties.class);
Validated validated = getAnnotation(type, Validated.class);

View File

@@ -28,6 +28,8 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.core.KotlinDetector;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -80,8 +82,9 @@ final class ConfigurationPropertiesBeanDefinitionRegistrar {
}
private static void assertHasAnnotation(Class<?> type) {
Assert.notNull(
AnnotationUtils.findAnnotation(type, ConfigurationProperties.class),
Assert.isTrue(
MergedAnnotations.from(type, SearchStrategy.EXHAUSTIVE)
.isPresent(ConfigurationProperties.class),
() -> "No " + ConfigurationProperties.class.getSimpleName()
+ " annotation found on '" + type.getName() + "'.");
}

View File

@@ -22,7 +22,9 @@ import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
@@ -83,40 +85,37 @@ public class DefaultErrorAttributes implements ErrorAttributes {
errorAttributes.put("timestamp", new Date());
errorAttributes.put("path", request.path());
Throwable error = getError(request);
HttpStatus errorStatus = determineHttpStatus(error);
MergedAnnotation<ResponseStatus> responseStatusAnnotation = MergedAnnotations
.from(error.getClass(), SearchStrategy.EXHAUSTIVE)
.get(ResponseStatus.class);
HttpStatus errorStatus = determineHttpStatus(error, responseStatusAnnotation);
errorAttributes.put("status", errorStatus.value());
errorAttributes.put("error", errorStatus.getReasonPhrase());
errorAttributes.put("message", determineMessage(error));
errorAttributes.put("message", determineMessage(error, responseStatusAnnotation));
errorAttributes.put("requestId", request.exchange().getRequest().getId());
handleException(errorAttributes, determineException(error), includeStackTrace);
return errorAttributes;
}
private HttpStatus determineHttpStatus(Throwable error) {
private HttpStatus determineHttpStatus(Throwable error,
MergedAnnotation<ResponseStatus> responseStatusAnnotation) {
if (error instanceof ResponseStatusException) {
return ((ResponseStatusException) error).getStatus();
}
ResponseStatus responseStatus = AnnotatedElementUtils
.findMergedAnnotation(error.getClass(), ResponseStatus.class);
if (responseStatus != null) {
return responseStatus.code();
}
return HttpStatus.INTERNAL_SERVER_ERROR;
return responseStatusAnnotation.getValue("code", HttpStatus.class)
.orElse(HttpStatus.INTERNAL_SERVER_ERROR);
}
private String determineMessage(Throwable error) {
private String determineMessage(Throwable error,
MergedAnnotation<ResponseStatus> responseStatusAnnotation) {
if (error instanceof WebExchangeBindException) {
return error.getMessage();
}
if (error instanceof ResponseStatusException) {
return ((ResponseStatusException) error).getReason();
}
ResponseStatus responseStatus = AnnotatedElementUtils
.findMergedAnnotation(error.getClass(), ResponseStatus.class);
if (responseStatus != null) {
return responseStatus.reason();
}
return error.getMessage();
return responseStatusAnnotation.getValue("reason", String.class)
.orElseGet(error::getMessage);
}
private Throwable determineException(Throwable error) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -37,7 +37,8 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.Assert;
import org.springframework.web.WebApplicationInitializer;
@@ -122,8 +123,9 @@ public abstract class SpringBootServletInitializer implements WebApplicationInit
builder = configure(builder);
builder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext));
SpringApplication application = builder.build();
if (application.getAllSources().isEmpty() && AnnotationUtils
.findAnnotation(getClass(), Configuration.class) != null) {
if (application.getAllSources().isEmpty()
&& MergedAnnotations.from(getClass(), SearchStrategy.EXHAUSTIVE)
.isPresent(Configuration.class)) {
application.addPrimarySources(Collections.singleton(getClass()));
}
Assert.state(!application.getAllSources().isEmpty(),