Compare commits

..

1 Commits

Author SHA1 Message Date
Spring Buildmaster 5acffaa72d Release v5.3.0 2020-10-27 14:44:42 +00:00
273 changed files with 2440 additions and 5875 deletions
+26 -26
View File
@@ -1,7 +1,7 @@
plugins {
id 'io.spring.dependency-management' version '1.0.9.RELEASE' apply false
id 'io.spring.nohttp' version '0.0.5.RELEASE'
id 'org.jetbrains.kotlin.jvm' version '1.4.21' apply false
id 'org.jetbrains.kotlin.jvm' version '1.4.10' apply false
id 'org.jetbrains.dokka' version '0.10.1' apply false
id 'org.asciidoctor.jvm.convert' version '3.1.0'
id 'org.asciidoctor.jvm.pdf' version '3.1.0'
@@ -9,7 +9,7 @@ plugins {
id "io.freefair.aspectj" version '5.1.1' apply false
id "com.github.ben-manes.versions" version '0.28.0'
id "me.champeau.gradle.jmh" version "0.5.0" apply false
id "org.jetbrains.kotlin.plugin.serialization" version "1.4.21" apply false
id "org.jetbrains.kotlin.plugin.serialization" version "1.4.10" apply false
}
ext {
@@ -25,18 +25,18 @@ configure(allprojects) { project ->
dependencyManagement {
imports {
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.0"
mavenBom "io.netty:netty-bom:4.1.54.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.2"
mavenBom "com.fasterxml.jackson:jackson-bom:2.11.3"
mavenBom "io.netty:netty-bom:4.1.53.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.0"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR8"
mavenBom "io.rsocket:rsocket-bom:1.1.0"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.35.v20201120"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.4.21"
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.4.2"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.33.v20201020"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.4.10"
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.4.0"
mavenBom "org.junit:junit-bom:5.7.0"
}
dependencies {
dependencySet(group: 'org.apache.logging.log4j', version: '2.14.0') {
dependencySet(group: 'org.apache.logging.log4j', version: '2.13.3') {
entry 'log4j-api'
entry 'log4j-core'
entry 'log4j-jul'
@@ -53,7 +53,7 @@ configure(allprojects) { project ->
entry 'aspectjtools'
entry 'aspectjweaver'
}
dependencySet(group: 'org.codehaus.groovy', version: '3.0.7') {
dependencySet(group: 'org.codehaus.groovy', version: '3.0.6') {
entry 'groovy'
entry 'groovy-jsr223'
entry 'groovy-templates' // requires findbugs for warning-free compilation
@@ -64,7 +64,7 @@ configure(allprojects) { project ->
dependency "io.reactivex:rxjava:1.3.8"
dependency "io.reactivex:rxjava-reactive-streams:1.2.1"
dependency "io.reactivex.rxjava2:rxjava:2.2.19"
dependency "io.reactivex.rxjava3:rxjava:3.0.8"
dependency "io.reactivex.rxjava3:rxjava:3.0.7"
dependency "io.projectreactor.tools:blockhound:1.0.4.RELEASE"
dependency "com.caucho:hessian:4.0.63"
@@ -73,9 +73,9 @@ configure(allprojects) { project ->
exclude group: "stax", name: "stax-api"
}
dependency "com.google.code.gson:gson:2.8.6"
dependency "com.google.protobuf:protobuf-java-util:3.14.0"
dependency "com.google.protobuf:protobuf-java-util:3.13.0"
dependency "com.googlecode.protobuf-java-format:protobuf-java-format:1.4"
dependency("com.thoughtworks.xstream:xstream:1.4.14") {
dependency("com.thoughtworks.xstream:xstream:1.4.13") {
exclude group: "xpp3", name: "xpp3_min"
exclude group: "xmlpull", name: "xmlpull"
}
@@ -96,7 +96,7 @@ configure(allprojects) { project ->
dependency "com.h2database:h2:1.4.200"
dependency "com.github.ben-manes.caffeine:caffeine:2.8.6"
dependency "com.github.librepdf:openpdf:1.3.23"
dependency "com.github.librepdf:openpdf:1.3.22"
dependency "com.rometools:rome:1.15.0"
dependency "commons-io:commons-io:2.5"
dependency "io.vavr:vavr:0.10.3"
@@ -123,23 +123,23 @@ configure(allprojects) { project ->
dependency "net.sf.ehcache:ehcache:2.10.6"
dependency "org.ehcache:jcache:1.0.1"
dependency "org.ehcache:ehcache:3.4.0"
dependency "org.hibernate:hibernate-core:5.4.25.Final"
dependency "org.hibernate:hibernate-core:5.4.22.Final"
dependency "org.hibernate:hibernate-validator:6.1.6.Final"
dependency "org.webjars:webjars-locator-core:0.46"
dependency "org.webjars:underscorejs:1.8.3"
dependencySet(group: 'org.apache.tomcat', version: '9.0.40') {
dependencySet(group: 'org.apache.tomcat', version: '9.0.39') {
entry 'tomcat-util'
entry('tomcat-websocket') {
exclude group: "org.apache.tomcat", name: "tomcat-websocket-api"
exclude group: "org.apache.tomcat", name: "tomcat-servlet-api"
}
}
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.40') {
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.39') {
entry 'tomcat-embed-core'
entry 'tomcat-embed-websocket'
}
dependencySet(group: 'io.undertow', version: '2.2.3.Final') {
dependencySet(group: 'io.undertow', version: '2.2.2.Final') {
entry 'undertow-core'
entry('undertow-websockets-jsr') {
exclude group: "org.jboss.spec.javax.websocket", name: "jboss-websocket-api_1.1_spec"
@@ -154,14 +154,14 @@ configure(allprojects) { project ->
entry 'okhttp'
entry 'mockwebserver'
}
dependency("org.apache.httpcomponents:httpclient:4.5.13") {
dependency("org.apache.httpcomponents:httpclient:4.5.12") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.apache.httpcomponents:httpasyncclient:4.1.4") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency 'org.apache.httpcomponents.client5:httpclient5:5.0.3'
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.0.3'
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.0.2'
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.4"
dependency "org.jruby:jruby:9.2.13.0"
@@ -190,25 +190,25 @@ configure(allprojects) { project ->
dependency "org.testng:testng:7.3.0"
dependency "org.hamcrest:hamcrest:2.1"
dependency "org.awaitility:awaitility:3.1.6"
dependency "org.assertj:assertj-core:3.18.1"
dependency "org.assertj:assertj-core:3.17.2"
dependencySet(group: 'org.xmlunit', version: '2.6.2') {
entry 'xmlunit-assertj'
entry('xmlunit-matchers') {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
}
dependencySet(group: 'org.mockito', version: '3.6.28') {
dependencySet(group: 'org.mockito', version: '3.5.15') {
entry('mockito-core') {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
entry 'mockito-junit-jupiter'
}
dependency "io.mockk:mockk:1.10.2"
dependency "io.mockk:mockk:1.10.0"
dependency("net.sourceforge.htmlunit:htmlunit:2.45.0") {
dependency("net.sourceforge.htmlunit:htmlunit:2.44.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:htmlunit-driver:2.45.0") {
dependency("org.seleniumhq.selenium:htmlunit-driver:2.44.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
@@ -339,7 +339,7 @@ configure([rootProject] + javaProjects) { project ->
}
checkstyle {
toolVersion = "8.38"
toolVersion = "8.36.2"
configDirectory.set(rootProject.file("src/checkstyle"))
}
-6
View File
@@ -1,9 +1,3 @@
logging:
level:
io.spring.concourse: DEBUG
distribute:
optional-deployments:
- '.*\\.zip'
spring:
main:
banner-mode: off
+3 -3
View File
@@ -37,17 +37,17 @@ anchors:
resource_types:
- name: artifactory-resource
type: registry-image
type: docker-image
source:
repository: springio/artifactory-resource
tag: 0.0.12
- name: github-status-resource
type: registry-image
type: docker-image
source:
repository: dpb587/github-status-resource
tag: master
- name: slack-notification
type: registry-image
type: docker-image
source:
repository: cfcommunity/slack-notification-resource
tag: latest
+2 -2
View File
@@ -6,11 +6,11 @@ CONFIG_DIR=git-repo/ci/config
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json
java -jar /opt/concourse-release-scripts.jar promote $RELEASE_TYPE $BUILD_INFO_LOCATION || { exit 1; }
java -jar /opt/concourse-release-scripts.jar promote $RELEASE_TYPE $BUILD_INFO_LOCATION > /dev/null || { exit 1; }
java -jar /opt/concourse-release-scripts.jar \
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
distribute $RELEASE_TYPE $BUILD_INFO_LOCATION || { exit 1; }
distribute $RELEASE_TYPE $BUILD_INFO_LOCATION > /dev/null || { exit 1; }
echo "Promotion complete"
echo $version > version/version
+1 -1
View File
@@ -1,4 +1,4 @@
version=5.3.2
version=5.3.0
org.gradle.jvmargs=-Xmx1536M
org.gradle.caching=true
org.gradle.parallel=true
+2 -2
View File
@@ -3,7 +3,7 @@ configurations {
}
dependencies {
asciidoctorExt("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.5.0")
asciidoctorExt("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.4.3.RELEASE")
}
repositories {
@@ -113,7 +113,7 @@ dokka {
}
task downloadResources(type: Download) {
def version = "0.2.5"
def version = "0.2.2.RELEASE"
src "https://repo.spring.io/release/io/spring/docresources/" +
"spring-doc-resources/$version/spring-doc-resources-${version}.zip"
dest project.file("$buildDir/docs/spring-doc-resources.zip")
+2 -18
View File
@@ -29,11 +29,12 @@ eclipse.classpath.file.whenMerged { classpath ->
classpath.entries.removeAll { entry -> (entry.path =~ /(?!.*?repack.*\.jar).*?\/([^\/]+)\/build\/libs\/[^\/]+\.jar/) }
}
// Use separate main/test outputs (prevents WTP from packaging test classes)
eclipse.classpath.defaultOutputDir = file(project.name+"/bin/eclipse")
eclipse.classpath.file.beforeMerged { classpath ->
classpath.entries.findAll{ it instanceof SourceFolder }.each {
if (it.output.startsWith("bin/")) {
if(it.output.startsWith("bin/")) {
it.output = null
}
}
@@ -55,23 +56,6 @@ eclipse.classpath.file.whenMerged { classpath ->
}
}
// Ensure that test fixture dependencies are handled properly in Gradle 6.7.
// Bug fixed in Gradle 6.8: https://github.com/gradle/gradle/issues/14932
eclipse.classpath.file.whenMerged {
entries.findAll { it instanceof ProjectDependency }.each {
it.entryAttributes.remove('without_test_code')
}
}
// Ensure that JMH sources and resources are treated as test classpath entries
// so that they can see test fixtures.
// https://github.com/melix/jmh-gradle-plugin/issues/157
eclipse.classpath.file.whenMerged {
entries.findAll { it.path =~ /src\/jmh\/(java|resources)/ }.each {
it.entryAttributes['test'] = 'true'
}
}
// Allow projects to be used as WTP modules
eclipse.project.natures "org.eclipse.wst.common.project.facet.core.nature"
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -350,8 +350,17 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
return this.discoveredThrowingType;
}
private static boolean isVariableName(String name) {
return AspectJProxyUtils.isVariableName(name);
private boolean isVariableName(String name) {
char[] chars = name.toCharArray();
if (!Character.isJavaIdentifierStart(chars[0])) {
return false;
}
for (int i = 1; i < chars.length; i++) {
if (!Character.isJavaIdentifierPart(chars[i])) {
return false;
}
}
return true;
}
@@ -631,6 +640,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// TODO AopUtils.invokeJoinpointUsingReflection
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
@@ -470,10 +470,22 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
*/
@Nullable
private String maybeExtractVariableName(@Nullable String candidateToken) {
if (AspectJProxyUtils.isVariableName(candidateToken)) {
if (!StringUtils.hasLength(candidateToken)) {
return null;
}
if (Character.isJavaIdentifierStart(candidateToken.charAt(0)) &&
Character.isLowerCase(candidateToken.charAt(0))) {
char[] tokenChars = candidateToken.toCharArray();
for (char tokenChar : tokenChars) {
if (!Character.isJavaIdentifierPart(tokenChar)) {
return null;
}
}
return candidateToken;
}
return null;
else {
return null;
}
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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,8 +21,6 @@ import java.util.List;
import org.springframework.aop.Advisor;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**
* Utility methods for working with AspectJ proxies.
@@ -75,19 +73,4 @@ public abstract class AspectJProxyUtils {
((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
}
static boolean isVariableName(@Nullable String name) {
if (!StringUtils.hasLength(name)) {
return false;
}
if (!Character.isJavaIdentifierStart(name.charAt(0))) {
return false;
}
for (int i = 1; i < name.length(); i++) {
if (!Character.isJavaIdentifierPart(name.charAt(i))) {
return false;
}
}
return true;
}
}
@@ -221,12 +221,10 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
@Override
@Nullable
public String[] getParameterNames() {
String[] parameterNames = this.parameterNames;
if (parameterNames == null) {
parameterNames = parameterNameDiscoverer.getParameterNames(getMethod());
this.parameterNames = parameterNames;
if (this.parameterNames == null) {
this.parameterNames = parameterNameDiscoverer.getParameterNames(getMethod());
}
return parameterNames;
return this.parameterNames;
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 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.
@@ -160,12 +160,23 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
}
/**
* Get the singleton aspect instance for the supplied aspect type.
* An instance is created if one cannot be found in the instance cache.
* Get the singleton aspect instance for the supplied aspect type. An instance
* is created if one cannot be found in the instance cache.
*/
private Object getSingletonAspectInstance(Class<?> aspectClass) {
return aspectCache.computeIfAbsent(aspectClass,
clazz -> new SimpleAspectInstanceFactory(clazz).getAspectInstance());
// Quick check without a lock...
Object instance = aspectCache.get(aspectClass);
if (instance == null) {
synchronized (aspectCache) {
// To be safe, check within full lock now...
instance = aspectCache.get(aspectClass);
if (instance == null) {
instance = new SimpleAspectInstanceFactory(aspectClass).getAspectInstance();
aspectCache.put(aspectClass, instance);
}
}
}
return instance;
}
@@ -51,7 +51,6 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConvertingComparator;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.MethodFilter;
import org.springframework.util.StringUtils;
import org.springframework.util.comparator.InstanceComparator;
@@ -71,11 +70,7 @@ import org.springframework.util.comparator.InstanceComparator;
@SuppressWarnings("serial")
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {
// Exclude @Pointcut methods
private static final MethodFilter adviceMethodFilter = ReflectionUtils.USER_DECLARED_METHODS
.and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));
private static final Comparator<Method> adviceMethodComparator;
private static final Comparator<Method> METHOD_COMPARATOR;
static {
// Note: although @After is ordered before @AfterReturning and @AfterThrowing,
@@ -91,7 +86,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
return (ann != null ? ann.getAnnotation() : null);
});
Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);
METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
}
@@ -165,10 +160,15 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
}
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
List<Method> methods = new ArrayList<>();
ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
final List<Method> methods = new ArrayList<>();
ReflectionUtils.doWithMethods(aspectClass, method -> {
// Exclude pointcuts
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
}, ReflectionUtils.USER_DECLARED_METHODS);
if (methods.size() > 1) {
methods.sort(adviceMethodComparator);
methods.sort(METHOD_COMPARATOR);
}
return methods;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 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.
@@ -114,15 +114,6 @@ public interface Advised extends TargetClassAware {
*/
Advisor[] getAdvisors();
/**
* Return the number of advisors applying to this proxy.
* <p>The default implementation delegates to {@code getAdvisors().length}.
* @since 5.3.1
*/
default int getAdvisorCount() {
return getAdvisors().length;
}
/**
* Add an advisor at the end of the advisor chain.
* <p>The Advisor may be an {@link org.springframework.aop.IntroductionAdvisor},
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -95,6 +95,12 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
*/
private List<Advisor> advisors = new ArrayList<>();
/**
* Array updated on changes to the advisors list, which is easier
* to manipulate internally.
*/
private Advisor[] advisorArray = new Advisor[0];
/**
* No-arg constructor for use as a JavaBean.
@@ -238,12 +244,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
@Override
public final Advisor[] getAdvisors() {
return this.advisors.toArray(new Advisor[0]);
}
@Override
public int getAdvisorCount() {
return this.advisors.size();
return this.advisorArray;
}
@Override
@@ -291,6 +292,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
}
}
updateAdvisorArray();
adviceChanged();
}
@@ -337,6 +339,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
Assert.notNull(advisor, "Advisor must not be null");
this.advisors.add(advisor);
}
updateAdvisorArray();
adviceChanged();
}
}
@@ -360,18 +363,27 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
"Illegal position " + pos + " in advisor list with size " + this.advisors.size());
}
this.advisors.add(pos, advisor);
updateAdvisorArray();
adviceChanged();
}
/**
* Bring the array up to date with the list.
*/
protected final void updateAdvisorArray() {
this.advisorArray = this.advisors.toArray(new Advisor[0]);
}
/**
* Allows uncontrolled access to the {@link List} of {@link Advisor Advisors}.
* <p>Use with care, and remember to {@link #adviceChanged() fire advice changed events}
* when making any modifications.
* <p>Use with care, and remember to {@link #updateAdvisorArray() refresh the advisor array}
* and {@link #adviceChanged() fire advice changed events} when making any modifications.
*/
protected final List<Advisor> getAdvisorsInternal() {
return this.advisors;
}
@Override
public void addAdvice(Advice advice) throws AopConfigException {
int pos = this.advisors.size();
@@ -509,6 +521,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
Assert.notNull(advisor, "Advisor must not be null");
this.advisors.add(advisor);
}
updateAdvisorArray();
adviceChanged();
}
@@ -523,6 +536,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
copy.advisorChainFactory = this.advisorChainFactory;
copy.interfaces = this.interfaces;
copy.advisors = this.advisors;
copy.updateAdvisorArray();
return copy;
}
@@ -539,6 +553,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
this.methodCache = new ConcurrentHashMap<>(32);
}
@Override
public String toProxyConfigString() {
return toString();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -206,7 +206,7 @@ public abstract class AopProxyUtils {
* Check equality of the advisors behind the given AdvisedSupport objects.
*/
public static boolean equalsAdvisors(AdvisedSupport a, AdvisedSupport b) {
return a.getAdvisorCount() == b.getAdvisorCount() && Arrays.equals(a.getAdvisors(), b.getAdvisors());
return Arrays.equals(a.getAdvisors(), b.getAdvisors());
}
@@ -125,7 +125,7 @@ class CglibAopProxy implements AopProxy, Serializable {
*/
public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
@@ -942,11 +942,11 @@ class CglibAopProxy implements AopProxy, Serializable {
}
// Advice instance identity is unimportant to the proxy class:
// All that matters is type and ordering.
if (this.advised.getAdvisorCount() != otherAdvised.getAdvisorCount()) {
return false;
}
Advisor[] thisAdvisors = this.advised.getAdvisors();
Advisor[] thatAdvisors = otherAdvised.getAdvisors();
if (thisAdvisors.length != thatAdvisors.length) {
return false;
}
for (int i = 0; i < thisAdvisors.length; i++) {
Advisor thisAdvisor = thisAdvisors[i];
Advisor thatAdvisor = thatAdvisors[i];
@@ -104,7 +104,7 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
*/
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2017 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.
@@ -59,8 +59,7 @@ public abstract aspect AbstractTransactionAspect extends TransactionAspectSuppor
@Override
public void destroy() {
// An aspect is basically a singleton -> cleanup on destruction
clearTransactionManagerCache();
clearTransactionManagerCache(); // An aspect is basically a singleton
}
@SuppressAjWarnings("adviceDidNotMatch")
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -422,12 +422,9 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
}
return;
}
if (this.suppressNotWritablePropertyException) {
// Optimization for common ignoreUnknown=true scenario since the
// exception would be caught and swallowed higher up anyway...
return;
else {
throw createNotWritablePropertyException(tokens.canonicalName);
}
throw createNotWritablePropertyException(tokens.canonicalName);
}
Object oldValue = null;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 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.
@@ -40,8 +40,6 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
private boolean autoGrowNestedPaths = false;
boolean suppressNotWritablePropertyException = false;
@Override
public void setExtractOldValueForEditor(boolean extractOldValueForEditor) {
@@ -91,41 +89,30 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
List<PropertyAccessException> propertyAccessExceptions = null;
List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
if (ignoreUnknown) {
this.suppressNotWritablePropertyException = true;
}
try {
for (PropertyValue pv : propertyValues) {
// setPropertyValue may throw any BeansException, which won't be caught
for (PropertyValue pv : propertyValues) {
try {
// This method may throw any BeansException, which won't be caught
// here, if there is a critical failure such as no matching field.
// We can attempt to deal only with less serious exceptions.
try {
setPropertyValue(pv);
}
catch (NotWritablePropertyException ex) {
if (!ignoreUnknown) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
catch (NullValueInNestedPathException ex) {
if (!ignoreInvalid) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
catch (PropertyAccessException ex) {
if (propertyAccessExceptions == null) {
propertyAccessExceptions = new ArrayList<>();
}
propertyAccessExceptions.add(ex);
}
setPropertyValue(pv);
}
}
finally {
if (ignoreUnknown) {
this.suppressNotWritablePropertyException = false;
catch (NotWritablePropertyException ex) {
if (!ignoreUnknown) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
catch (NullValueInNestedPathException ex) {
if (!ignoreInvalid) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
catch (PropertyAccessException ex) {
if (propertyAccessExceptions == null) {
propertyAccessExceptions = new ArrayList<>();
}
propertyAccessExceptions.add(ex);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 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.
@@ -92,7 +92,8 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
@Override
protected NotWritablePropertyException createNotWritablePropertyException(String propertyName) {
PropertyMatches matches = PropertyMatches.forField(propertyName, getRootClass());
throw new NotWritablePropertyException(getRootClass(), getNestedPath() + propertyName,
throw new NotWritablePropertyException(
getRootClass(), getNestedPath() + propertyName,
matches.buildErrorMessage(), matches.getPossibleMatches());
}
@@ -644,20 +644,21 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
synchronized (this) {
if (!this.cached) {
Object cachedFieldValue = null;
if (value != null || this.required) {
cachedFieldValue = desc;
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
cachedFieldValue = new ShortcutDependencyDescriptor(
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
this.cachedFieldValue = cachedFieldValue;
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
@@ -26,6 +26,9 @@ import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.support.RootBeanDefinition;
@@ -66,6 +69,8 @@ public class InjectionMetadata {
};
private static final Log logger = LogFactory.getLog(InjectionMetadata.class);
private final Class<?> targetClass;
private final Collection<InjectedElement> injectedElements;
@@ -105,6 +110,9 @@ public class InjectionMetadata {
if (!beanDefinition.isExternallyManagedConfigMember(member)) {
beanDefinition.registerExternallyManagedConfigMember(member);
checkedElements.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Registered injected element on class [" + this.targetClass.getName() + "]: " + element);
}
}
}
this.checkedElements = checkedElements;
@@ -116,6 +124,9 @@ public class InjectionMetadata {
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
@@ -141,12 +152,12 @@ public class InjectionMetadata {
* Return an {@code InjectionMetadata} instance, possibly for empty elements.
* @param elements the elements to inject (possibly empty)
* @param clazz the target class
* @return a new {@link #InjectionMetadata(Class, Collection)} instance
* @return a new {@link #InjectionMetadata(Class, Collection)} instance,
* or {@link #EMPTY} in case of no elements
* @since 5.2
*/
public static InjectionMetadata forElements(Collection<InjectedElement> elements, Class<?> clazz) {
return (elements.isEmpty() ? new InjectionMetadata(clazz, Collections.emptyList()) :
new InjectionMetadata(clazz, elements));
return (elements.isEmpty() ? InjectionMetadata.EMPTY : new InjectionMetadata(clazz, elements));
}
/**
@@ -1288,8 +1288,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
* @param registry the PropertyEditorRegistry to initialize
*/
protected void registerCustomEditors(PropertyEditorRegistry registry) {
if (registry instanceof PropertyEditorRegistrySupport) {
((PropertyEditorRegistrySupport) registry).useConfigValueEditors();
PropertyEditorRegistrySupport registrySupport =
(registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null);
if (registrySupport != null) {
registrySupport.useConfigValueEditors();
}
if (!this.propertyEditorRegistrars.isEmpty()) {
for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) {
@@ -67,7 +67,6 @@ import org.springframework.util.StringUtils;
/**
* Delegate for resolving constructors and factory methods.
*
* <p>Performs constructor resolution through argument matching.
*
* @author Juergen Hoeller
@@ -86,7 +85,7 @@ class ConstructorResolver {
private static final Object[] EMPTY_ARGS = new Object[0];
/**
* Marker for autowired arguments in a cached argument array, to be replaced
* Marker for autowired arguments in a cached argument array, to be later replaced
* by a {@linkplain #resolveAutowiredArgument resolved autowired argument}.
*/
private static final Object autowiredArgumentMarker = new Object();
@@ -150,7 +149,7 @@ class ConstructorResolver {
}
}
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
}
@@ -411,7 +410,6 @@ class ConstructorResolver {
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
throw new ImplicitlyAppearedSingletonException();
}
this.beanFactory.registerDependentBean(factoryBeanName, beanName);
factoryClass = factoryBean.getClass();
isStatic = false;
}
@@ -446,7 +444,7 @@ class ConstructorResolver {
}
}
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve);
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
}
}
@@ -818,7 +816,7 @@ class ConstructorResolver {
* Resolve the prepared arguments stored in the given bean definition.
*/
private Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
Executable executable, Object[] argsToResolve) {
Executable executable, Object[] argsToResolve, boolean fallback) {
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
@@ -831,7 +829,7 @@ class ConstructorResolver {
Object argValue = argsToResolve[argIndex];
MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex);
if (argValue == autowiredArgumentMarker) {
argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, true);
argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, fallback);
}
else if (argValue instanceof BeanMetadataElement) {
argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
@@ -63,8 +63,9 @@ public class BeanFactoryUtilsTests {
@BeforeEach
public void setup() {
public void setUp() {
// Interesting hierarchical factory to test counts.
// Slow to read so we cache it.
DefaultListableBeanFactory grandParent = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(grandParent).loadBeanDefinitions(ROOT_CONTEXT);
@@ -92,7 +93,7 @@ public class BeanFactoryUtilsTests {
* Check that override doesn't count as two separate beans.
*/
@Test
public void testHierarchicalCountBeansWithOverride() {
public void testHierarchicalCountBeansWithOverride() throws Exception {
// Leaf count
assertThat(this.listableBeanFactory.getBeanDefinitionCount() == 1).isTrue();
// Count minus duplicate
@@ -100,14 +101,14 @@ public class BeanFactoryUtilsTests {
}
@Test
public void testHierarchicalNamesWithNoMatch() {
public void testHierarchicalNamesWithNoMatch() throws Exception {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, NoOp.class));
assertThat(names.size()).isEqualTo(0);
}
@Test
public void testHierarchicalNamesWithMatchOnlyInRoot() {
public void testHierarchicalNamesWithMatchOnlyInRoot() throws Exception {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, IndexedTestBean.class));
assertThat(names.size()).isEqualTo(1);
@@ -117,7 +118,7 @@ public class BeanFactoryUtilsTests {
}
@Test
public void testGetBeanNamesForTypeWithOverride() {
public void testGetBeanNamesForTypeWithOverride() throws Exception {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class));
// includes 2 TestBeans from FactoryBeans (DummyFactory definitions)
@@ -235,7 +236,7 @@ public class BeanFactoryUtilsTests {
}
@Test
public void testHierarchicalResolutionWithOverride() {
public void testHierarchicalResolutionWithOverride() throws Exception {
Object test3 = this.listableBeanFactory.getBean("test3");
Object test = this.listableBeanFactory.getBean("test");
@@ -275,14 +276,14 @@ public class BeanFactoryUtilsTests {
}
@Test
public void testHierarchicalNamesForAnnotationWithNoMatch() {
public void testHierarchicalNamesForAnnotationWithNoMatch() throws Exception {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.listableBeanFactory, Override.class));
assertThat(names.size()).isEqualTo(0);
}
@Test
public void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() {
public void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() throws Exception {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.listableBeanFactory, TestAnnotation.class));
assertThat(names.size()).isEqualTo(1);
@@ -292,7 +293,7 @@ public class BeanFactoryUtilsTests {
}
@Test
public void testGetBeanNamesForAnnotationWithOverride() {
public void testGetBeanNamesForAnnotationWithOverride() throws Exception {
AnnotatedBean annotatedBean = new AnnotatedBean();
this.listableBeanFactory.registerSingleton("anotherAnnotatedBean", annotatedBean);
List<String> names = Arrays.asList(
@@ -432,7 +433,6 @@ public class BeanFactoryUtilsTests {
String basePackage() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@ControllerAdvice
@interface RestControllerAdvice {
@@ -444,23 +444,18 @@ public class BeanFactoryUtilsTests {
String basePackage() default "";
}
@ControllerAdvice("com.example")
static class ControllerAdviceClass {
}
@RestControllerAdvice("com.example")
static class RestControllerAdviceClass {
}
static class TestBeanSmartFactoryBean implements SmartFactoryBean<TestBean> {
private final TestBean testBean = new TestBean("enigma", 42);
private final boolean singleton;
private final boolean prototype;
TestBeanSmartFactoryBean(boolean singleton, boolean prototype) {
@@ -483,7 +478,7 @@ public class BeanFactoryUtilsTests {
return TestBean.class;
}
public TestBean getObject() {
public TestBean getObject() throws Exception {
// We don't really care if the actual instance is a singleton or prototype
// for the tests that use this factory.
return this.testBean;
@@ -785,13 +785,12 @@ class DefaultListableBeanFactoryTests {
factory.registerBeanDefinition("child", childDefinition);
factory.registerAlias("parent", "alias");
TestBean child = factory.getBean("child", TestBean.class);
TestBean child = (TestBean) factory.getBean("child");
assertThat(child.getName()).isEqualTo(EXPECTED_NAME);
assertThat(child.getAge()).isEqualTo(EXPECTED_AGE);
BeanDefinition mergedBeanDefinition1 = factory.getMergedBeanDefinition("child");
BeanDefinition mergedBeanDefinition2 = factory.getMergedBeanDefinition("child");
Object mergedBeanDefinition2 = factory.getMergedBeanDefinition("child");
assertThat(mergedBeanDefinition1).as("Use cached merged bean definition").isSameAs(mergedBeanDefinition2);
assertThat(mergedBeanDefinition2).as("Use cached merged bean definition").isEqualTo(mergedBeanDefinition2);
}
@Test
@@ -1839,7 +1838,8 @@ class DefaultListableBeanFactoryTests {
assertThat(factoryBean).as("The FactoryBean should have been registered.").isNotNull();
FactoryBeanDependentBean bean = (FactoryBeanDependentBean) lbf.autowire(FactoryBeanDependentBean.class,
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
assertThat(bean.getFactoryBean()).as("The FactoryBeanDependentBean should have been autowired 'by type' with the LazyInitFactory.").isEqualTo(factoryBean);
Object mergedBeanDefinition2 = bean.getFactoryBean();
assertThat(mergedBeanDefinition2).as("The FactoryBeanDependentBean should have been autowired 'by type' with the LazyInitFactory.").isEqualTo(mergedBeanDefinition2);
}
@Test
@@ -2388,7 +2388,8 @@ class DefaultListableBeanFactoryTests {
BeanWithDestroyMethod.closeCount = 0;
lbf.preInstantiateSingletons();
lbf.destroySingletons();
assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(1);
Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount;
assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2);
}
@Test
@@ -2402,7 +2403,8 @@ class DefaultListableBeanFactoryTests {
BeanWithDestroyMethod.closeCount = 0;
lbf.preInstantiateSingletons();
lbf.destroySingletons();
assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(2);
Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount;
assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2);
}
@Test
@@ -2417,7 +2419,8 @@ class DefaultListableBeanFactoryTests {
BeanWithDestroyMethod.closeCount = 0;
lbf.preInstantiateSingletons();
lbf.destroySingletons();
assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(1);
Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount;
assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2);
}
@Test
@@ -2539,15 +2542,14 @@ class DefaultListableBeanFactoryTests {
factory.registerBeanDefinition("child", child);
AbstractBeanDefinition def = (AbstractBeanDefinition) factory.getBeanDefinition("child");
assertThat(def.getScope()).as("Child 'scope' not overriding parent scope (it must).").isEqualTo(theChildScope);
Object mergedBeanDefinition2 = def.getScope();
assertThat(mergedBeanDefinition2).as("Child 'scope' not overriding parent scope (it must).").isEqualTo(mergedBeanDefinition2);
}
@Test
void scopeInheritanceForChildBeanDefinitions() {
String theParentScope = "bonanza!";
RootBeanDefinition parent = new RootBeanDefinition();
parent.setScope(theParentScope);
parent.setScope("bonanza!");
AbstractBeanDefinition child = new ChildBeanDefinition("parent");
child.setBeanClass(TestBean.class);
@@ -2557,7 +2559,8 @@ class DefaultListableBeanFactoryTests {
factory.registerBeanDefinition("child", child);
BeanDefinition def = factory.getMergedBeanDefinition("child");
assertThat(def.getScope()).as("Child 'scope' not inherited").isEqualTo(theParentScope);
Object mergedBeanDefinition2 = def.getScope();
assertThat(mergedBeanDefinition2).as("Child 'scope' not inherited").isEqualTo(mergedBeanDefinition2);
}
@Test
@@ -2593,12 +2596,15 @@ class DefaultListableBeanFactoryTests {
});
lbf.preInstantiateSingletons();
TestBean tb = (TestBean) lbf.getBean("test");
assertThat(tb.getName()).as("Name was set on field by IAPP").isEqualTo(nameSetOnField);
Object mergedBeanDefinition2 = tb.getName();
assertThat(mergedBeanDefinition2).as("Name was set on field by IAPP").isEqualTo(mergedBeanDefinition2);
if (!skipPropertyPopulation) {
assertThat(tb.getAge()).as("Property value still set").isEqualTo(ageSetByPropertyValue);
Object mergedBeanDefinition21 = tb.getAge();
assertThat(mergedBeanDefinition21).as("Property value still set").isEqualTo(mergedBeanDefinition21);
}
else {
assertThat(tb.getAge()).as("Property value was NOT set and still has default value").isEqualTo(0);
Object mergedBeanDefinition21 = tb.getAge();
assertThat(mergedBeanDefinition21).as("Property value was NOT set and still has default value").isEqualTo(mergedBeanDefinition21);
}
}
@@ -155,7 +155,8 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
* @param name the name of the cache to be added
*/
private void updateCacheNames(String name) {
Set<String> cacheNames = new LinkedHashSet<>(this.cacheNames);
Set<String> cacheNames = new LinkedHashSet<>(this.cacheNames.size() + 1);
cacheNames.addAll(this.cacheNames);
cacheNames.add(name);
this.cacheNames = Collections.unmodifiableSet(cacheNames);
}
@@ -99,7 +99,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
* @see #setBeanNameGenerator
*/
public static final AnnotationBeanNameGenerator IMPORT_BEAN_NAME_GENERATOR =
FullyQualifiedAnnotationBeanNameGenerator.INSTANCE;
new FullyQualifiedAnnotationBeanNameGenerator();
private static final String IMPORT_REGISTRY_BEAN_NAME =
ConfigurationClassPostProcessor.class.getName() + ".importRegistry";
@@ -427,11 +427,15 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
if (configBeanDefs.isEmpty() || IN_NATIVE_IMAGE) {
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
enhanceConfigClasses.end();
return;
}
if (IN_NATIVE_IMAGE) {
throw new BeanDefinitionStoreException("@Configuration classes need to be marked as " +
"proxyBeanMethods=false. Found: " + configBeanDefs.keySet());
}
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
@@ -43,15 +43,6 @@ import org.springframework.util.Assert;
*/
public class FullyQualifiedAnnotationBeanNameGenerator extends AnnotationBeanNameGenerator {
/**
* A convenient constant for a default {@code FullyQualifiedAnnotationBeanNameGenerator}
* instance, as used for configuration-level import purposes.
* @since 5.2.11
*/
public static final FullyQualifiedAnnotationBeanNameGenerator INSTANCE =
new FullyQualifiedAnnotationBeanNameGenerator();
@Override
protected String buildDefaultBeanName(BeanDefinition definition) {
String beanClassName = definition.getBeanClassName();
@@ -25,6 +25,8 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.ResolvableType;
import org.springframework.core.metrics.ApplicationStartup;
import org.springframework.core.metrics.StartupStep;
import org.springframework.lang.Nullable;
import org.springframework.util.ErrorHandler;
@@ -55,6 +57,9 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM
@Nullable
private ErrorHandler errorHandler;
@Nullable
private ApplicationStartup applicationStartup;
/**
* Create a new SimpleApplicationEventMulticaster.
@@ -122,6 +127,22 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM
return this.errorHandler;
}
/**
* Set the {@link ApplicationStartup} to track event listener invocations during startup.
* @since 5.3
*/
public void setApplicationStartup(@Nullable ApplicationStartup applicationStartup) {
this.applicationStartup = applicationStartup;
}
/**
* Return the current application startup for this multicaster.
*/
@Nullable
public ApplicationStartup getApplicationStartup() {
return this.applicationStartup;
}
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
@@ -135,6 +156,16 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else if (this.applicationStartup != null) {
StartupStep invocationStep = this.applicationStartup.start("spring.event.invoke-listener");
invokeListener(listener, event);
invocationStep.tag("event", event::toString);
if (eventType != null) {
invocationStep.tag("eventType", eventType::toString);
}
invocationStep.tag("listener", listener::toString);
invocationStep.end();
}
else {
invokeListener(listener, event);
}
@@ -815,7 +815,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
simpleApplicationEventMulticaster.setApplicationStartup(getApplicationStartup());
this.applicationEventMulticaster = simpleApplicationEventMulticaster;
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 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.
@@ -106,6 +106,7 @@ public @interface DateTimeFormat {
/**
* The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSXXX},
* e.g. "2000-10-31T01:30:00.000-05:00".
* <p>This is the default if no annotation value is specified.
*/
DATE_TIME,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -36,26 +36,24 @@ import static org.assertj.core.api.Assertions.assertThat;
public class AtAspectJAfterThrowingTests {
@Test
public void testAccessThrowable() {
public void testAccessThrowable() throws Exception {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
ITestBean bean = (ITestBean) ctx.getBean("testBean");
ExceptionHandlingAspect aspect = (ExceptionHandlingAspect) ctx.getBean("aspect");
assertThat(AopUtils.isAopProxy(bean)).isTrue();
IOException exceptionThrown = null;
try {
bean.unreliableFileOperation();
}
catch (IOException ex) {
exceptionThrown = ex;
catch (IOException e) {
//
}
assertThat(aspect.handled).isEqualTo(1);
assertThat(aspect.lastException).isSameAs(exceptionThrown);
assertThat(aspect.lastException).isNotNull();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -36,7 +36,6 @@ import static org.assertj.core.api.Assertions.assertThat;
public class AtAspectJAnnotationBindingTests {
private AnnotatedTestBean testBean;
private ClassPathXmlApplicationContext ctx;
@@ -71,7 +70,8 @@ public class AtAspectJAnnotationBindingTests {
class AtAspectJAnnotationBindingTestAspect {
@Around("execution(* *(..)) && @annotation(testAnn)")
public Object doWithAnnotation(ProceedingJoinPoint pjp, TestAnnotation testAnn) throws Throwable {
public Object doWithAnnotation(ProceedingJoinPoint pjp, TestAnnotation testAnn)
throws Throwable {
String annValue = testAnn.value();
Object result = pjp.proceed();
return (result instanceof String ? annValue + " " + result : result);
@@ -20,6 +20,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -65,6 +66,7 @@ import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -75,13 +77,13 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
* @author Juergen Hoeller
* @author Sam Brannen
*/
class ConfigurationClassPostProcessorTests {
public class ConfigurationClassPostProcessorTests {
private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
@BeforeEach
void setup() {
public void setup() {
QualifierAnnotationAutowireCandidateResolver acr = new QualifierAnnotationAutowireCandidateResolver();
acr.setBeanFactory(this.beanFactory);
this.beanFactory.setAutowireCandidateResolver(acr);
@@ -97,7 +99,7 @@ class ConfigurationClassPostProcessorTests {
* We test for such a case below, and in doing so prove that enhancement is working.
*/
@Test
void enhancementIsPresentBecauseSingletonSemanticsAreRespected() {
public void enhancementIsPresentBecauseSingletonSemanticsAreRespected() {
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(SingletonBeanConfig.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
@@ -105,13 +107,11 @@ class ConfigurationClassPostProcessorTests {
Foo foo = beanFactory.getBean("foo", Foo.class);
Bar bar = beanFactory.getBean("bar", Bar.class);
assertThat(bar.foo).isSameAs(foo);
assertThat(beanFactory.getDependentBeans("foo")).contains("bar");
assertThat(beanFactory.getDependentBeans("config")).contains("foo");
assertThat(beanFactory.getDependentBeans("config")).contains("bar");
assertThat(Arrays.asList(beanFactory.getDependentBeans("foo")).contains("bar")).isTrue();
}
@Test
void enhancementIsPresentBecauseSingletonSemanticsAreRespectedUsingAsm() {
public void enhancementIsPresentBecauseSingletonSemanticsAreRespectedUsingAsm() {
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(SingletonBeanConfig.class.getName()));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
@@ -119,13 +119,11 @@ class ConfigurationClassPostProcessorTests {
Foo foo = beanFactory.getBean("foo", Foo.class);
Bar bar = beanFactory.getBean("bar", Bar.class);
assertThat(bar.foo).isSameAs(foo);
assertThat(beanFactory.getDependentBeans("foo")).contains("bar");
assertThat(beanFactory.getDependentBeans("config")).contains("foo");
assertThat(beanFactory.getDependentBeans("config")).contains("bar");
assertThat(Arrays.asList(beanFactory.getDependentBeans("foo")).contains("bar")).isTrue();
}
@Test
void enhancementIsNotPresentForProxyBeanMethodsFlagSetToFalse() {
public void enhancementIsNotPresentForProxyBeanMethodsFlagSetToFalse() {
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(NonEnhancedSingletonBeanConfig.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
@@ -136,7 +134,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void enhancementIsNotPresentForProxyBeanMethodsFlagSetToFalseUsingAsm() {
public void enhancementIsNotPresentForProxyBeanMethodsFlagSetToFalseUsingAsm() {
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(NonEnhancedSingletonBeanConfig.class.getName()));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
@@ -147,7 +145,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void enhancementIsNotPresentForStaticMethods() {
public void enhancementIsNotPresentForStaticMethods() {
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(StaticSingletonBeanConfig.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
@@ -160,7 +158,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void enhancementIsNotPresentForStaticMethodsUsingAsm() {
public void enhancementIsNotPresentForStaticMethodsUsingAsm() {
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(StaticSingletonBeanConfig.class.getName()));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
@@ -173,7 +171,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void configurationIntrospectionOfInnerClassesWorksWithDotNameSyntax() {
public void configurationIntrospectionOfInnerClassesWorksWithDotNameSyntax() {
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(getClass().getName() + ".SingletonBeanConfig"));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
@@ -187,7 +185,7 @@ class ConfigurationClassPostProcessorTests {
* if a bean class is already loaded.
*/
@Test
void alreadyLoadedConfigurationClasses() {
public void alreadyLoadedConfigurationClasses() {
beanFactory.registerBeanDefinition("unloadedConfig", new RootBeanDefinition(UnloadedConfig.class.getName()));
beanFactory.registerBeanDefinition("loadedConfig", new RootBeanDefinition(LoadedConfig.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
@@ -200,7 +198,7 @@ class ConfigurationClassPostProcessorTests {
* Tests whether a bean definition without a specified bean class is handled correctly.
*/
@Test
void postProcessorIntrospectsInheritedDefinitionsCorrectly() {
public void postProcessorIntrospectsInheritedDefinitionsCorrectly() {
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(SingletonBeanConfig.class));
beanFactory.registerBeanDefinition("parent", new RootBeanDefinition(TestBean.class));
beanFactory.registerBeanDefinition("child", new ChildBeanDefinition("parent"));
@@ -212,96 +210,96 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void postProcessorWorksWithComposedConfigurationUsingReflection() {
public void postProcessorWorksWithComposedConfigurationUsingReflection() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(ComposedConfigurationClass.class);
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
void postProcessorWorksWithComposedConfigurationUsingAsm() {
public void postProcessorWorksWithComposedConfigurationUsingAsm() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(ComposedConfigurationClass.class.getName());
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForBasePackageUsingReflection() {
public void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForBasePackageUsingReflection() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ComposedConfigurationWithAttributeOverrideForBasePackage.class);
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForBasePackageUsingAsm() {
public void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForBasePackageUsingAsm() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ComposedConfigurationWithAttributeOverrideForBasePackage.class.getName());
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForExcludeFilterUsingReflection() {
public void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForExcludeFilterUsingReflection() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ComposedConfigurationWithAttributeOverrideForExcludeFilter.class);
assertSupportForComposedAnnotationWithExclude(beanDefinition);
}
@Test
void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForExcludeFilterUsingAsm() {
public void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForExcludeFilterUsingAsm() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ComposedConfigurationWithAttributeOverrideForExcludeFilter.class.getName());
assertSupportForComposedAnnotationWithExclude(beanDefinition);
}
@Test
void postProcessorWorksWithExtendedConfigurationWithAttributeOverrideForExcludesFilterUsingReflection() {
public void postProcessorWorksWithExtendedConfigurationWithAttributeOverrideForExcludesFilterUsingReflection() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ExtendedConfigurationWithAttributeOverrideForExcludeFilter.class);
assertSupportForComposedAnnotationWithExclude(beanDefinition);
}
@Test
void postProcessorWorksWithExtendedConfigurationWithAttributeOverrideForExcludesFilterUsingAsm() {
public void postProcessorWorksWithExtendedConfigurationWithAttributeOverrideForExcludesFilterUsingAsm() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ExtendedConfigurationWithAttributeOverrideForExcludeFilter.class.getName());
assertSupportForComposedAnnotationWithExclude(beanDefinition);
}
@Test
void postProcessorWorksWithComposedComposedConfigurationWithAttributeOverridesUsingReflection() {
public void postProcessorWorksWithComposedComposedConfigurationWithAttributeOverridesUsingReflection() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ComposedComposedConfigurationWithAttributeOverridesClass.class);
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
void postProcessorWorksWithComposedComposedConfigurationWithAttributeOverridesUsingAsm() {
public void postProcessorWorksWithComposedComposedConfigurationWithAttributeOverridesUsingAsm() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ComposedComposedConfigurationWithAttributeOverridesClass.class.getName());
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesUsingReflection() {
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesUsingReflection() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
MetaComponentScanConfigurationWithAttributeOverridesClass.class);
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesUsingAsm() {
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesUsingAsm() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
MetaComponentScanConfigurationWithAttributeOverridesClass.class.getName());
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesSubclassUsingReflection() {
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesSubclassUsingReflection() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
SubMetaComponentScanConfigurationWithAttributeOverridesClass.class);
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesSubclassUsingAsm() {
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesSubclassUsingAsm() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
SubMetaComponentScanConfigurationWithAttributeOverridesClass.class.getName());
assertSupportForComposedAnnotation(beanDefinition);
@@ -326,7 +324,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void postProcessorOverridesNonApplicationBeanDefinitions() {
public void postProcessorOverridesNonApplicationBeanDefinitions() {
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
rbd.setRole(RootBeanDefinition.ROLE_SUPPORT);
beanFactory.registerBeanDefinition("bar", rbd);
@@ -339,7 +337,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void postProcessorDoesNotOverrideRegularBeanDefinitions() {
public void postProcessorDoesNotOverrideRegularBeanDefinitions() {
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
rbd.setResource(new DescriptiveResource("XML or something"));
beanFactory.registerBeanDefinition("bar", rbd);
@@ -351,7 +349,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void postProcessorDoesNotOverrideRegularBeanDefinitionsEvenWithScopedProxy() {
public void postProcessorDoesNotOverrideRegularBeanDefinitionsEvenWithScopedProxy() {
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
rbd.setResource(new DescriptiveResource("XML or something"));
BeanDefinitionHolder proxied = ScopedProxyUtils.createScopedProxy(
@@ -365,7 +363,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void postProcessorFailsOnImplicitOverrideIfOverridingIsNotAllowed() {
public void postProcessorFailsOnImplicitOverrideIfOverridingIsNotAllowed() {
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
rbd.setResource(new DescriptiveResource("XML or something"));
beanFactory.registerBeanDefinition("bar", rbd);
@@ -380,7 +378,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test // gh-25430
void detectAliasOverride() {
public void detectAliasOverride() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
beanFactory.setAllowBeanDefinitionOverriding(false);
@@ -392,7 +390,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void configurationClassesProcessedInCorrectOrder() {
public void configurationClassesProcessedInCorrectOrder() {
beanFactory.registerBeanDefinition("config1", new RootBeanDefinition(OverridingSingletonBeanConfig.class));
beanFactory.registerBeanDefinition("config2", new RootBeanDefinition(SingletonBeanConfig.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
@@ -406,7 +404,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void configurationClassesWithValidOverridingForProgrammaticCall() {
public void configurationClassesWithValidOverridingForProgrammaticCall() {
beanFactory.registerBeanDefinition("config1", new RootBeanDefinition(OverridingAgainSingletonBeanConfig.class));
beanFactory.registerBeanDefinition("config2", new RootBeanDefinition(OverridingSingletonBeanConfig.class));
beanFactory.registerBeanDefinition("config3", new RootBeanDefinition(SingletonBeanConfig.class));
@@ -421,7 +419,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void configurationClassesWithInvalidOverridingForProgrammaticCall() {
public void configurationClassesWithInvalidOverridingForProgrammaticCall() {
beanFactory.registerBeanDefinition("config1", new RootBeanDefinition(InvalidOverridingSingletonBeanConfig.class));
beanFactory.registerBeanDefinition("config2", new RootBeanDefinition(OverridingSingletonBeanConfig.class));
beanFactory.registerBeanDefinition("config3", new RootBeanDefinition(SingletonBeanConfig.class));
@@ -437,7 +435,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test // SPR-15384
void nestedConfigurationClassesProcessedInCorrectOrder() {
public void nestedConfigurationClassesProcessedInCorrectOrder() {
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithOrderedNestedClasses.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
@@ -450,7 +448,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test // SPR-16734
void innerConfigurationClassesProcessedInCorrectOrder() {
public void innerConfigurationClassesProcessedInCorrectOrder() {
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithOrderedInnerClasses.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
@@ -464,7 +462,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void scopedProxyTargetMarkedAsNonAutowireCandidate() {
public void scopedProxyTargetMarkedAsNonAutowireCandidate() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(bpp);
@@ -481,7 +479,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void processingAllowedOnlyOncePerProcessorRegistryPair() {
public void processingAllowedOnlyOncePerProcessorRegistryPair() {
DefaultListableBeanFactory bf1 = new DefaultListableBeanFactory();
DefaultListableBeanFactory bf2 = new DefaultListableBeanFactory();
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
@@ -494,7 +492,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjection() {
public void genericsBasedInjection() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(bpp);
@@ -511,7 +509,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithScoped() {
public void genericsBasedInjectionWithScoped() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(bpp);
@@ -528,7 +526,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithScopedProxy() {
public void genericsBasedInjectionWithScopedProxy() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(bpp);
@@ -548,7 +546,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithScopedProxyUsingAsm() {
public void genericsBasedInjectionWithScopedProxyUsingAsm() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(bpp);
@@ -568,7 +566,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithImplTypeAtInjectionPoint() {
public void genericsBasedInjectionWithImplTypeAtInjectionPoint() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(bpp);
@@ -585,7 +583,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithFactoryBean() {
public void genericsBasedInjectionWithFactoryBean() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(bpp);
@@ -604,7 +602,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithRawMatch() {
public void genericsBasedInjectionWithRawMatch() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawMatchingConfiguration.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
@@ -613,7 +611,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithWildcardMatch() {
public void genericsBasedInjectionWithWildcardMatch() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardMatchingConfiguration.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
@@ -622,7 +620,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithWildcardWithExtendsMatch() {
public void genericsBasedInjectionWithWildcardWithExtendsMatch() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardWithExtendsConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
@@ -630,7 +628,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithWildcardWithGenericExtendsMatch() {
public void genericsBasedInjectionWithWildcardWithGenericExtendsMatch() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardWithGenericExtendsConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
@@ -638,12 +636,12 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithEarlyGenericsMatching() {
public void genericsBasedInjectionWithEarlyGenericsMatching() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertThat(beanNames).contains("stringRepo");
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertThat(beanNames.length).isEqualTo(1);
@@ -655,13 +653,13 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithLateGenericsMatching() {
public void genericsBasedInjectionWithLateGenericsMatching() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
beanFactory.preInstantiateSingletons();
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertThat(beanNames).contains("stringRepo");
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertThat(beanNames.length).isEqualTo(1);
@@ -673,12 +671,12 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithEarlyGenericsMatchingAndRawFactoryMethod() {
public void genericsBasedInjectionWithEarlyGenericsMatchingAndRawFactoryMethod() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawFactoryMethodRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertThat(beanNames).contains("stringRepo");
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertThat(beanNames.length).isEqualTo(0);
@@ -688,13 +686,13 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithLateGenericsMatchingAndRawFactoryMethod() {
public void genericsBasedInjectionWithLateGenericsMatchingAndRawFactoryMethod() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawFactoryMethodRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
beanFactory.preInstantiateSingletons();
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertThat(beanNames).contains("stringRepo");
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertThat(beanNames.length).isEqualTo(1);
@@ -706,12 +704,12 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithEarlyGenericsMatchingAndRawInstance() {
public void genericsBasedInjectionWithEarlyGenericsMatchingAndRawInstance() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawInstanceRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertThat(beanNames).contains("stringRepo");
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertThat(beanNames.length).isEqualTo(1);
@@ -723,13 +721,13 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithLateGenericsMatchingAndRawInstance() {
public void genericsBasedInjectionWithLateGenericsMatchingAndRawInstance() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawInstanceRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
beanFactory.preInstantiateSingletons();
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertThat(beanNames).contains("stringRepo");
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertThat(beanNames.length).isEqualTo(1);
@@ -741,7 +739,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithEarlyGenericsMatchingOnCglibProxy() {
public void genericsBasedInjectionWithEarlyGenericsMatchingOnCglibProxy() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
@@ -751,7 +749,7 @@ class ConfigurationClassPostProcessorTests {
beanFactory.registerSingleton("traceInterceptor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertThat(beanNames).contains("stringRepo");
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertThat(beanNames.length).isEqualTo(1);
@@ -765,7 +763,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxy() {
public void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxy() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
@@ -776,7 +774,7 @@ class ConfigurationClassPostProcessorTests {
beanFactory.preInstantiateSingletons();
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertThat(beanNames).contains("stringRepo");
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertThat(beanNames.length).isEqualTo(1);
@@ -790,7 +788,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxyAndRawFactoryMethod() {
public void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxyAndRawFactoryMethod() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawFactoryMethodRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
@@ -801,7 +799,7 @@ class ConfigurationClassPostProcessorTests {
beanFactory.preInstantiateSingletons();
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertThat(beanNames).contains("stringRepo");
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertThat(beanNames.length).isEqualTo(1);
@@ -815,7 +813,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxyAndRawInstance() {
public void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxyAndRawInstance() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawInstanceRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
@@ -826,7 +824,7 @@ class ConfigurationClassPostProcessorTests {
beanFactory.preInstantiateSingletons();
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertThat(beanNames).contains("stringRepo");
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertThat(beanNames.length).isEqualTo(1);
@@ -840,7 +838,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithEarlyGenericsMatchingOnJdkProxy() {
public void genericsBasedInjectionWithEarlyGenericsMatchingOnJdkProxy() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
@@ -849,7 +847,7 @@ class ConfigurationClassPostProcessorTests {
beanFactory.registerSingleton("traceInterceptor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
String[] beanNames = beanFactory.getBeanNamesForType(RepositoryInterface.class);
assertThat(beanNames).contains("stringRepo");
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
assertThat(beanNames.length).isEqualTo(1);
@@ -863,7 +861,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxy() {
public void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxy() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
@@ -873,7 +871,7 @@ class ConfigurationClassPostProcessorTests {
beanFactory.preInstantiateSingletons();
String[] beanNames = beanFactory.getBeanNamesForType(RepositoryInterface.class);
assertThat(beanNames).contains("stringRepo");
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
assertThat(beanNames.length).isEqualTo(1);
@@ -887,7 +885,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxyAndRawFactoryMethod() {
public void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxyAndRawFactoryMethod() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawFactoryMethodRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
@@ -897,7 +895,7 @@ class ConfigurationClassPostProcessorTests {
beanFactory.preInstantiateSingletons();
String[] beanNames = beanFactory.getBeanNamesForType(RepositoryInterface.class);
assertThat(beanNames).contains("stringRepo");
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
assertThat(beanNames.length).isEqualTo(1);
@@ -911,7 +909,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxyAndRawInstance() {
public void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxyAndRawInstance() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawInstanceRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
@@ -921,7 +919,7 @@ class ConfigurationClassPostProcessorTests {
beanFactory.preInstantiateSingletons();
String[] beanNames = beanFactory.getBeanNamesForType(RepositoryInterface.class);
assertThat(beanNames).contains("stringRepo");
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
assertThat(beanNames.length).isEqualTo(1);
@@ -935,7 +933,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testSelfReferenceExclusionForFactoryMethodOnSameBean() {
public void testSelfReferenceExclusionForFactoryMethodOnSameBean() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(bpp);
@@ -949,7 +947,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testConfigWithDefaultMethods() {
public void testConfigWithDefaultMethods() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(bpp);
@@ -963,7 +961,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testConfigWithDefaultMethodsUsingAsm() {
public void testConfigWithDefaultMethodsUsingAsm() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(bpp);
@@ -977,7 +975,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testCircularDependency() {
public void testCircularDependency() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(bpp);
@@ -990,38 +988,38 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testCircularDependencyWithApplicationContext() {
public void testCircularDependencyWithApplicationContext() {
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() ->
new AnnotationConfigApplicationContext(A.class, AStrich.class))
.withMessageContaining("Circular reference");
}
@Test
void testPrototypeArgumentThroughBeanMethodCall() {
public void testPrototypeArgumentThroughBeanMethodCall() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanArgumentConfigWithPrototype.class);
ctx.getBean(FooFactory.class).createFoo(new BarArgument());
}
@Test
void testSingletonArgumentThroughBeanMethodCall() {
public void testSingletonArgumentThroughBeanMethodCall() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanArgumentConfigWithSingleton.class);
ctx.getBean(FooFactory.class).createFoo(new BarArgument());
}
@Test
void testNullArgumentThroughBeanMethodCall() {
public void testNullArgumentThroughBeanMethodCall() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanArgumentConfigWithNull.class);
ctx.getBean("aFoo");
}
@Test
void testInjectionPointMatchForNarrowTargetReturnType() {
public void testInjectionPointMatchForNarrowTargetReturnType() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(FooBarConfiguration.class);
assertThat(ctx.getBean(FooImpl.class).bar).isSameAs(ctx.getBean(BarImpl.class));
}
@Test
void testVarargOnBeanMethod() {
public void testVarargOnBeanMethod() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(VarargConfiguration.class, TestBean.class);
VarargConfiguration bean = ctx.getBean(VarargConfiguration.class);
assertThat(bean.testBeans).isNotNull();
@@ -1030,7 +1028,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testEmptyVarargOnBeanMethod() {
public void testEmptyVarargOnBeanMethod() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(VarargConfiguration.class);
VarargConfiguration bean = ctx.getBean(VarargConfiguration.class);
assertThat(bean.testBeans).isNotNull();
@@ -1038,7 +1036,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testCollectionArgumentOnBeanMethod() {
public void testCollectionArgumentOnBeanMethod() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(CollectionArgumentConfiguration.class, TestBean.class);
CollectionArgumentConfiguration bean = ctx.getBean(CollectionArgumentConfiguration.class);
assertThat(bean.testBeans).isNotNull();
@@ -1047,7 +1045,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testEmptyCollectionArgumentOnBeanMethod() {
public void testEmptyCollectionArgumentOnBeanMethod() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(CollectionArgumentConfiguration.class);
CollectionArgumentConfiguration bean = ctx.getBean(CollectionArgumentConfiguration.class);
assertThat(bean.testBeans).isNotNull();
@@ -1055,7 +1053,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testMapArgumentOnBeanMethod() {
public void testMapArgumentOnBeanMethod() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MapArgumentConfiguration.class, DummyRunnable.class);
MapArgumentConfiguration bean = ctx.getBean(MapArgumentConfiguration.class);
assertThat(bean.testBeans).isNotNull();
@@ -1064,7 +1062,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testEmptyMapArgumentOnBeanMethod() {
public void testEmptyMapArgumentOnBeanMethod() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MapArgumentConfiguration.class);
MapArgumentConfiguration bean = ctx.getBean(MapArgumentConfiguration.class);
assertThat(bean.testBeans).isNotNull();
@@ -1072,7 +1070,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testCollectionInjectionFromSameConfigurationClass() {
public void testCollectionInjectionFromSameConfigurationClass() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(CollectionInjectionConfiguration.class);
CollectionInjectionConfiguration bean = ctx.getBean(CollectionInjectionConfiguration.class);
assertThat(bean.testBeans).isNotNull();
@@ -1081,7 +1079,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testMapInjectionFromSameConfigurationClass() {
public void testMapInjectionFromSameConfigurationClass() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MapInjectionConfiguration.class);
MapInjectionConfiguration bean = ctx.getBean(MapInjectionConfiguration.class);
assertThat(bean.testBeans).isNotNull();
@@ -1090,7 +1088,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testBeanLookupFromSameConfigurationClass() {
public void testBeanLookupFromSameConfigurationClass() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanLookupConfiguration.class);
BeanLookupConfiguration bean = ctx.getBean(BeanLookupConfiguration.class);
assertThat(bean.getTestBean()).isNotNull();
@@ -1098,7 +1096,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testNameClashBetweenConfigurationClassAndBean() {
public void testNameClashBetweenConfigurationClassAndBean() {
assertThatExceptionOfType(BeanDefinitionStoreException.class).isThrownBy(() -> {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyTestBean.class);
ctx.getBean("myTestBean", TestBean.class);
@@ -1106,7 +1104,7 @@ class ConfigurationClassPostProcessorTests {
}
@Test
void testBeanDefinitionRegistryPostProcessorConfig() {
public void testBeanDefinitionRegistryPostProcessorConfig() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanDefinitionRegistryPostProcessorConfig.class);
boolean condition = ctx.getBean("myTestBean") instanceof TestBean;
assertThat(condition).isTrue();
@@ -307,23 +307,6 @@ public class ConfigurationClassProcessingTests {
assertThat(tb.getLawyer()).isEqualTo(ctx.getBean(NestedTestBean.class));
}
@Test // gh-26019
public void autowiringWithDynamicPrototypeBeanClass() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
ConfigWithDynamicPrototype.class, PrototypeDependency.class);
PrototypeInterface p1 = ctx.getBean(PrototypeInterface.class, 1);
assertThat(p1).isInstanceOf(PrototypeOne.class);
assertThat(((PrototypeOne) p1).prototypeDependency).isNotNull();
PrototypeInterface p2 = ctx.getBean(PrototypeInterface.class, 2);
assertThat(p2).isInstanceOf(PrototypeTwo.class);
PrototypeInterface p3 = ctx.getBean(PrototypeInterface.class, 1);
assertThat(p3).isInstanceOf(PrototypeOne.class);
assertThat(((PrototypeOne) p3).prototypeDependency).isNotNull();
}
/**
* Creates a new {@link BeanFactory}, populates it with a {@link BeanDefinition}
@@ -649,42 +632,4 @@ public class ConfigurationClassProcessingTests {
}
}
static class PrototypeDependency {
}
interface PrototypeInterface {
}
static class PrototypeOne extends AbstractPrototype {
@Autowired
PrototypeDependency prototypeDependency;
}
static class PrototypeTwo extends AbstractPrototype {
// no autowired dependency here, in contrast to above
}
static class AbstractPrototype implements PrototypeInterface {
}
@Configuration
static class ConfigWithDynamicPrototype {
@Bean
@Scope(value = "prototype")
public PrototypeInterface getDemoBean( int i) {
switch ( i) {
case 1: return new PrototypeOne();
case 2:
default:
return new PrototypeTwo();
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -58,10 +58,10 @@ internal fun <T: Any> monoToDeferred(source: Mono<T>) =
* @since 5.2
*/
@Suppress("UNCHECKED_CAST")
fun invokeSuspendingFunction(method: Method, target: Any, vararg args: Any?): Publisher<*> {
fun invokeSuspendingFunction(method: Method, bean: Any, vararg args: Any?): Publisher<*> {
val function = method.kotlinFunction!!
val mono = mono(Dispatchers.Unconfined) {
function.callSuspend(target, *args.sliceArray(0..(args.size-2))).let { if (it == Unit) null else it }
function.callSuspend(bean, *args.sliceArray(0..(args.size-2))).let { if (it == Unit) null else it }
}.onErrorMap(InvocationTargetException::class.java) { it.targetException }
return if (function.returnType.classifier == Flow::class) {
mono.flatMapMany { (it as Flow<Any>).asFlux() }
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -225,11 +225,11 @@ public final class Conventions {
if (!attributeName.contains("-")) {
return attributeName;
}
char[] result = new char[attributeName.length() -1]; // not completely accurate but good guess
char[] chars = attributeName.toCharArray();
char[] result = new char[chars.length -1]; // not completely accurate but good guess
int currPos = 0;
boolean upperCaseNext = false;
for (int i = 0; i < attributeName.length(); i++ ) {
char c = attributeName.charAt(i);
for (char c : chars) {
if (c == '-') {
upperCaseNext = true;
}
@@ -264,12 +264,14 @@ public class ReactiveAdapterRegistry {
registry.registerReactiveType(
ReactiveTypeDescriptor.multiValue(io.reactivex.Observable.class, io.reactivex.Observable::empty),
source -> ((io.reactivex.Observable<?>) source).toFlowable(io.reactivex.BackpressureStrategy.BUFFER),
io.reactivex.Observable::fromPublisher
source -> io.reactivex.Flowable.fromPublisher(source)
.toObservable()
);
registry.registerReactiveType(
ReactiveTypeDescriptor.singleRequiredValue(io.reactivex.Single.class),
source -> ((io.reactivex.Single<?>) source).toFlowable(),
io.reactivex.Single::fromPublisher
source -> io.reactivex.Flowable.fromPublisher(source)
.toObservable().singleElement().toSingle()
);
registry.registerReactiveType(
ReactiveTypeDescriptor.singleOptionalValue(io.reactivex.Maybe.class, io.reactivex.Maybe::empty),
@@ -280,7 +282,8 @@ public class ReactiveAdapterRegistry {
registry.registerReactiveType(
ReactiveTypeDescriptor.noValue(io.reactivex.Completable.class, io.reactivex.Completable::complete),
source -> ((io.reactivex.Completable) source).toFlowable(),
io.reactivex.Completable::fromPublisher
source -> io.reactivex.Flowable.fromPublisher(source)
.toObservable().ignoreElements()
);
}
}
@@ -301,26 +304,30 @@ public class ReactiveAdapterRegistry {
io.reactivex.rxjava3.core.Observable::empty),
source -> ((io.reactivex.rxjava3.core.Observable<?>) source).toFlowable(
io.reactivex.rxjava3.core.BackpressureStrategy.BUFFER),
io.reactivex.rxjava3.core.Observable::fromPublisher
source -> io.reactivex.rxjava3.core.Flowable.fromPublisher(source)
.toObservable()
);
registry.registerReactiveType(
ReactiveTypeDescriptor.singleRequiredValue(io.reactivex.rxjava3.core.Single.class),
source -> ((io.reactivex.rxjava3.core.Single<?>) source).toFlowable(),
io.reactivex.rxjava3.core.Single::fromPublisher
source -> io.reactivex.rxjava3.core.Flowable.fromPublisher(source)
.toObservable().singleElement().toSingle()
);
registry.registerReactiveType(
ReactiveTypeDescriptor.singleOptionalValue(
io.reactivex.rxjava3.core.Maybe.class,
io.reactivex.rxjava3.core.Maybe::empty),
source -> ((io.reactivex.rxjava3.core.Maybe<?>) source).toFlowable(),
io.reactivex.rxjava3.core.Maybe::fromPublisher
source -> io.reactivex.rxjava3.core.Flowable.fromPublisher(source)
.toObservable().singleElement()
);
registry.registerReactiveType(
ReactiveTypeDescriptor.noValue(
io.reactivex.rxjava3.core.Completable.class,
io.reactivex.rxjava3.core.Completable::complete),
source -> ((io.reactivex.rxjava3.core.Completable) source).toFlowable(),
io.reactivex.rxjava3.core.Completable::fromPublisher
source -> io.reactivex.rxjava3.core.Flowable.fromPublisher(source)
.toObservable().ignoreElements()
);
}
}
@@ -21,6 +21,9 @@ import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
/**
@@ -47,6 +50,8 @@ public final class SpringProperties {
private static final String PROPERTIES_RESOURCE_LOCATION = "spring.properties";
private static final Log logger = LogFactory.getLog(SpringProperties.class);
private static final Properties localProperties = new Properties();
@@ -56,13 +61,16 @@ public final class SpringProperties {
URL url = (cl != null ? cl.getResource(PROPERTIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResource(PROPERTIES_RESOURCE_LOCATION));
if (url != null) {
logger.debug("Found 'spring.properties' file in local classpath");
try (InputStream is = url.openStream()) {
localProperties.load(is);
}
}
}
catch (IOException ex) {
System.err.println("Could not load 'spring.properties' file from local classpath: " + ex);
if (logger.isInfoEnabled()) {
logger.info("Could not load 'spring.properties' file from local classpath: " + ex);
}
}
}
@@ -100,7 +108,9 @@ public final class SpringProperties {
value = System.getProperty(key);
}
catch (Throwable ex) {
System.err.println("Could not retrieve system property '" + key + "': " + ex);
if (logger.isDebugEnabled()) {
logger.debug("Could not retrieve system property '" + key + "': " + ex);
}
}
}
return value;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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,8 +18,8 @@ package org.springframework.core.annotation;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.IntFunction;
@@ -31,11 +31,10 @@ import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* {@link Collector} implementations that provide various reduction operations for
* Collector implementations that provide various reduction operations for
* {@link MergedAnnotation} instances.
*
* @author Phillip Webb
* @author Sam Brannen
* @since 5.2
*/
public abstract class MergedAnnotationCollectors {
@@ -53,16 +52,13 @@ public abstract class MergedAnnotationCollectors {
* Create a new {@link Collector} that accumulates merged annotations to a
* {@link LinkedHashSet} containing {@linkplain MergedAnnotation#synthesize()
* synthesized} versions.
* <p>The collector returned by this method is effectively equivalent to
* {@code Collectors.mapping(MergedAnnotation::synthesize, Collectors.toCollection(LinkedHashSet::new))}
* but avoids the creation of a composite collector.
* @param <A> the annotation type
* @return a {@link Collector} which collects and synthesizes the
* annotations into a {@link Set}
*/
public static <A extends Annotation> Collector<MergedAnnotation<A>, ?, Set<A>> toAnnotationSet() {
return Collector.of(LinkedHashSet::new, (set, annotation) -> set.add(annotation.synthesize()),
MergedAnnotationCollectors::combiner);
return Collector.of(ArrayList<A>::new, (list, annotation) -> list.add(annotation.synthesize()),
MergedAnnotationCollectors::addAll, LinkedHashSet::new);
}
/**
@@ -94,14 +90,14 @@ public abstract class MergedAnnotationCollectors {
IntFunction<R[]> generator) {
return Collector.of(ArrayList::new, (list, annotation) -> list.add(annotation.synthesize()),
MergedAnnotationCollectors::combiner, list -> list.toArray(generator.apply(list.size())));
MergedAnnotationCollectors::addAll, list -> list.toArray(generator.apply(list.size())));
}
/**
* Create a new {@link Collector} that accumulates merged annotations to a
* Create a new {@link Collector} that accumulates merged annotations to an
* {@link MultiValueMap} with items {@linkplain MultiValueMap#add(Object, Object)
* added} from each merged annotation
* {@linkplain MergedAnnotation#asMap(Adapt...) as a map}.
* {@link MergedAnnotation#asMap(Adapt...) as a map}.
* @param <A> the annotation type
* @param adaptations the adaptations that should be applied to the annotation values
* @return a {@link Collector} which collects and synthesizes the
@@ -115,13 +111,13 @@ public abstract class MergedAnnotationCollectors {
}
/**
* Create a new {@link Collector} that accumulates merged annotations to a
* Create a new {@link Collector} that accumulates merged annotations to an
* {@link MultiValueMap} with items {@linkplain MultiValueMap#add(Object, Object)
* added} from each merged annotation
* {@linkplain MergedAnnotation#asMap(Adapt...) as a map}.
* {@link MergedAnnotation#asMap(Adapt...) as a map}.
* @param <A> the annotation type
* @param finisher the finisher function for the new {@link MultiValueMap}
* @param adaptations the adaptations that should be applied to the annotation values
* @param finisher the finisher function for the new {@link MultiValueMap}
* @return a {@link Collector} which collects and synthesizes the
* annotations into a {@link LinkedMultiValueMap}
* @see #toMultiValueMap(MergedAnnotation.Adapt...)
@@ -134,7 +130,7 @@ public abstract class MergedAnnotationCollectors {
IDENTITY_FINISH_CHARACTERISTICS : NO_CHARACTERISTICS);
return Collector.of(LinkedMultiValueMap::new,
(map, annotation) -> annotation.asMap(adaptations).forEach(map::add),
MergedAnnotationCollectors::combiner, finisher, characteristics);
MergedAnnotationCollectors::merge, finisher, characteristics);
}
@@ -142,22 +138,13 @@ public abstract class MergedAnnotationCollectors {
return instance == candidate;
}
/**
* {@link Collector#combiner() Combiner} for collections.
* <p>This method is only invoked if the {@link java.util.stream.Stream} is
* processed in {@linkplain java.util.stream.Stream#parallel() parallel}.
*/
private static <E, C extends Collection<E>> C combiner(C collection, C additions) {
collection.addAll(additions);
return collection;
private static <E, L extends List<E>> L addAll(L list, L additions) {
list.addAll(additions);
return list;
}
/**
* {@link Collector#combiner() Combiner} for multi-value maps.
* <p>This method is only invoked if the {@link java.util.stream.Stream} is
* processed in {@linkplain java.util.stream.Stream#parallel() parallel}.
*/
private static <K, V> MultiValueMap<K, V> combiner(MultiValueMap<K, V> map, MultiValueMap<K, V> additions) {
private static <K, V> MultiValueMap<K, V> merge(MultiValueMap<K, V> map,
MultiValueMap<K, V> additions) {
map.addAll(additions);
return map;
}
@@ -21,8 +21,6 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
@@ -150,22 +148,4 @@ public abstract class Hints {
}
}
/**
* If the hints contain a {@link #LOG_PREFIX_HINT} and the given logger has
* DEBUG level enabled, apply the log prefix as a hint to the given buffer
* via {@link DataBufferUtils#touch(DataBuffer, Object)}.
* @param buffer the buffer to touch
* @param hints the hints map to check for a log prefix
* @param logger the logger whose level to check
* @since 5.3.2
*/
public static void touchDataBuffer(DataBuffer buffer, @Nullable Map<String, Object> hints, Log logger) {
if (logger.isDebugEnabled() && hints != null) {
Object logPrefix = hints.get(LOG_PREFIX_HINT);
if (logPrefix != null) {
DataBufferUtils.touch(buffer, logPrefix);
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -130,9 +130,6 @@ public class ResourceRegionEncoder extends AbstractEncoder<ResourceRegion> {
}
Flux<DataBuffer> in = DataBufferUtils.read(resource, position, bufferFactory, this.bufferSize);
if (logger.isDebugEnabled()) {
in = in.doOnNext(buffer -> Hints.touchDataBuffer(buffer, hints, logger));
}
return DataBufferUtils.takeUntilByteCount(in, count);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -118,7 +118,7 @@ public final class Property {
}
// Package private
// package private
MethodParameter getMethodParameter() {
return this.methodParameter;
@@ -132,7 +132,7 @@ public final class Property {
}
// Internal helpers
// internal helpers
private String resolveName() {
if (this.readMethod != null) {
@@ -142,13 +142,10 @@ public final class Property {
}
else {
index = this.readMethod.getName().indexOf("is");
if (index != -1) {
index += 2;
}
else {
// Record-style plain accessor method, e.g. name()
index = 0;
if (index == -1) {
throw new IllegalArgumentException("Not a getter method");
}
index += 2;
}
return StringUtils.uncapitalize(this.readMethod.getName().substring(index));
}
@@ -17,17 +17,17 @@
package org.springframework.core.convert.support;
import java.lang.reflect.Array;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.CopyOnWriteArraySet;
import org.springframework.core.DecoratingProxy;
import org.springframework.core.ResolvableType;
@@ -500,9 +500,9 @@ public class GenericConversionService implements ConfigurableConversionService {
*/
private static class Converters {
private final Set<GenericConverter> globalConverters = new CopyOnWriteArraySet<>();
private final Set<GenericConverter> globalConverters = new LinkedHashSet<>();
private final Map<ConvertiblePair, ConvertersForPair> converters = new ConcurrentHashMap<>(256);
private final Map<ConvertiblePair, ConvertersForPair> converters = new LinkedHashMap<>(36);
public void add(GenericConverter converter) {
Set<ConvertiblePair> convertibleTypes = converter.getConvertibleTypes();
@@ -513,7 +513,8 @@ public class GenericConversionService implements ConfigurableConversionService {
}
else {
for (ConvertiblePair convertiblePair : convertibleTypes) {
getMatchableConverters(convertiblePair).add(converter);
ConvertersForPair convertersForPair = getMatchableConverters(convertiblePair);
convertersForPair.add(converter);
}
}
}
@@ -651,7 +652,7 @@ public class GenericConversionService implements ConfigurableConversionService {
*/
private static class ConvertersForPair {
private final Deque<GenericConverter> converters = new ConcurrentLinkedDeque<>();
private final Deque<GenericConverter> converters = new ArrayDeque<>(1);
public void add(GenericConverter converter) {
this.converters.addFirst(converter);
@@ -487,24 +487,6 @@ public abstract class DataBufferUtils {
}
}
/**
* Associate the given hint with the data buffer if it is a pooled buffer
* and supports leak tracking.
* @param dataBuffer the data buffer to attach the hint to
* @param hint the hint to attach
* @return the input buffer
* @since 5.3.2
*/
@SuppressWarnings("unchecked")
public static <T extends DataBuffer> T touch(T dataBuffer, Object hint) {
if (dataBuffer instanceof PooledDataBuffer) {
return (T) ((PooledDataBuffer) dataBuffer).touch(hint);
}
else {
return dataBuffer;
}
}
/**
* Release the given data buffer, if it is a {@link PooledDataBuffer} and
* has been {@linkplain PooledDataBuffer#isAllocated() allocated}.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -54,8 +54,11 @@ public class LimitedDataBufferList extends ArrayList<DataBuffer> {
@Override
public boolean add(DataBuffer buffer) {
updateCount(buffer.readableByteCount());
return super.add(buffer);
boolean result = super.add(buffer);
if (result) {
updateCount(buffer.readableByteCount());
}
return result;
}
@Override
@@ -315,12 +315,6 @@ public class NettyDataBuffer implements PooledDataBuffer {
return new NettyDataBuffer(this.byteBuf.retain(), this.dataBufferFactory);
}
@Override
public PooledDataBuffer touch(Object hint) {
this.byteBuf.touch(hint);
return this;
}
@Override
public boolean release() {
return this.byteBuf.release();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 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.
@@ -38,13 +38,6 @@ public interface PooledDataBuffer extends DataBuffer {
*/
PooledDataBuffer retain();
/**
* Associate the given hint with the data buffer for debugging purposes.
* @return this buffer
* @since 5.3.2
*/
PooledDataBuffer touch(Object hint);
/**
* Decrease the reference count for this buffer by one,
* and deallocate it once the count reaches zero.
@@ -432,9 +432,6 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
// Possibly "c:" drive prefix on Windows, to be upper-cased for proper duplicate detection
filePath = StringUtils.capitalize(filePath);
}
// # can appear in directories/filenames, java.net.URL should not treat it as a fragment
filePath = StringUtils.replace(filePath, "#", "%23");
// Build URL that points to the root of the jar file
UrlResource jarResource = new UrlResource(ResourceUtils.JAR_URL_PREFIX +
ResourceUtils.FILE_URL_PREFIX + filePath + ResourceUtils.JAR_URL_SEPARATOR);
// Potentially overlapping with URLClassLoader.getURLs() result above!
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 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,11 +18,10 @@ package org.springframework.core.io.support;
import java.beans.PropertyEditorSupport;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -130,7 +129,7 @@ public class ResourceArrayPropertyEditor extends PropertyEditorSupport {
public void setValue(Object value) throws IllegalArgumentException {
if (value instanceof Collection || (value instanceof Object[] && !(value instanceof Resource[]))) {
Collection<?> input = (value instanceof Collection ? (Collection<?>) value : Arrays.asList((Object[]) value));
Set<Resource> merged = new LinkedHashSet<>();
List<Resource> merged = new ArrayList<>();
for (Object element : input) {
if (element instanceof String) {
// A location pattern: resolve it into a Resource array.
@@ -138,7 +137,11 @@ public class ResourceArrayPropertyEditor extends PropertyEditorSupport {
String pattern = resolvePath((String) element).trim();
try {
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
Collections.addAll(merged, resources);
for (Resource resource : resources) {
if (!merged.contains(resource)) {
merged.add(resource);
}
}
}
catch (IOException ex) {
// ignore - might be an unresolved placeholder or non-existing base directory
@@ -149,7 +152,10 @@ public class ResourceArrayPropertyEditor extends PropertyEditorSupport {
}
else if (element instanceof Resource) {
// A Resource object: add it to the result.
merged.add((Resource) element);
Resource resource = (Resource) element;
if (!merged.contains(resource)) {
merged.add(resource);
}
}
else {
throw new IllegalArgumentException("Cannot convert element [" + element + "] to [" +
@@ -644,7 +644,7 @@ public class AntPathMatcher implements PathMatcher {
private static final Pattern GLOB_PATTERN = Pattern.compile("\\?|\\*|\\{((?:\\{[^/]+?}|[^/{}]|\\\\[{}])+?)}");
private static final String DEFAULT_VARIABLE_PATTERN = "((?s).*)";
private static final String DEFAULT_VARIABLE_PATTERN = "(.*)";
private final String rawPattern;
@@ -16,8 +16,6 @@
package org.springframework.util;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.BitSet;
@@ -106,7 +104,7 @@ public class MimeType implements Comparable<MimeType>, Serializable {
private final Map<String, String> parameters;
@Nullable
private transient Charset resolvedCharset;
private Charset resolvedCharset;
@Nullable
private volatile String toStringValue;
@@ -186,9 +184,9 @@ public class MimeType implements Comparable<MimeType>, Serializable {
this.subtype = subtype.toLowerCase(Locale.ENGLISH);
if (!CollectionUtils.isEmpty(parameters)) {
Map<String, String> map = new LinkedCaseInsensitiveMap<>(parameters.size(), Locale.ENGLISH);
parameters.forEach((parameter, value) -> {
checkParameters(parameter, value);
map.put(parameter, value);
parameters.forEach((attribute, value) -> {
checkParameters(attribute, value);
map.put(attribute, value);
});
this.parameters = Collections.unmodifiableMap(map);
}
@@ -226,11 +224,11 @@ public class MimeType implements Comparable<MimeType>, Serializable {
}
}
protected void checkParameters(String parameter, String value) {
Assert.hasLength(parameter, "'parameter' must not be empty");
protected void checkParameters(String attribute, String value) {
Assert.hasLength(attribute, "'attribute' must not be empty");
Assert.hasLength(value, "'value' must not be empty");
checkToken(parameter);
if (PARAM_CHARSET.equals(parameter)) {
checkToken(attribute);
if (PARAM_CHARSET.equals(attribute)) {
if (this.resolvedCharset == null) {
this.resolvedCharset = Charset.forName(unquote(value));
}
@@ -593,17 +591,6 @@ public class MimeType implements Comparable<MimeType>, Serializable {
return 0;
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization, just initialize state after deserialization.
ois.defaultReadObject();
// Initialize transient fields.
String charsetName = getParameter(PARAM_CHARSET);
if (charsetName != null) {
this.resolvedCharset = Charset.forName(unquote(charsetName));
}
}
/**
* Parse the given String value into a {@code MimeType} object,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -824,19 +824,6 @@ public abstract class ReflectionUtils {
* @param method the method to check
*/
boolean matches(Method method);
/**
* Create a composite filter based on this filter <em>and</em> the provided filter.
* <p>If this filter does not match, the next filter will not be applied.
* @param next the next {@code MethodFilter}
* @return a composite {@code MethodFilter}
* @throws IllegalArgumentException if the MethodFilter argument is {@code null}
* @since 5.3.2
*/
default MethodFilter and(MethodFilter next) {
Assert.notNull(next, "Next MethodFilter must not be null");
return method -> matches(method) && next.matches(method);
}
}
@@ -865,19 +852,6 @@ public abstract class ReflectionUtils {
* @param field the field to check
*/
boolean matches(Field field);
/**
* Create a composite filter based on this filter <em>and</em> the provided filter.
* <p>If this filter does not match, the next filter will not be applied.
* @param next the next {@code FieldFilter}
* @return a composite {@code FieldFilter}
* @throws IllegalArgumentException if the FieldFilter argument is {@code null}
* @since 5.3.2
*/
default FieldFilter and(FieldFilter next) {
Assert.notNull(next, "Next FieldFilter must not be null");
return field -> matches(field) && next.matches(field);
}
}
}
@@ -161,8 +161,9 @@ class XMLEventStreamWriter implements XMLStreamWriter {
public void writeEndElement() throws XMLStreamException {
closeEmptyElementIfNecessary();
int last = this.endElements.size() - 1;
EndElement lastEndElement = this.endElements.remove(last);
EndElement lastEndElement = this.endElements.get(last);
this.eventWriter.add(lastEndElement);
this.endElements.remove(last);
}
@Override
@@ -367,9 +367,8 @@ class ReactiveAdapterRegistryTests {
private static class ExtendedFlux<T> extends Flux<T> {
@Override
public void subscribe(CoreSubscriber<? super T> actual) {
public void subscribe(CoreSubscriber actual) {
throw new UnsupportedOperationException();
}
}
}
@@ -35,8 +35,6 @@ import java.util.List;
import java.util.concurrent.CountDownLatch;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import org.junit.jupiter.api.Test;
import org.mockito.stubbing.Answer;
import org.reactivestreams.Subscription;
import reactor.core.publisher.BaseSubscriber;
@@ -836,22 +834,6 @@ class DataBufferUtilsTests extends AbstractDataBufferAllocatingTests {
.verifyError(DataBufferLimitException.class);
}
@Test // gh-26060
void joinWithLimitDoesNotOverRelease() {
NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(PooledByteBufAllocator.DEFAULT);
byte[] bytes = "foo-bar-baz".getBytes(StandardCharsets.UTF_8);
NettyDataBuffer buffer = bufferFactory.allocateBuffer(bytes.length);
buffer.getNativeBuffer().retain(); // should be at 2 now
buffer.write(bytes);
Mono<DataBuffer> result = DataBufferUtils.join(Flux.just(buffer), 8);
StepVerifier.create(result).verifyError(DataBufferLimitException.class);
assertThat(buffer.getNativeBuffer().refCnt()).isEqualTo(1);
buffer.release();
}
@ParameterizedDataBufferAllocatingTest
void joinErrors(String displayName, DataBufferFactory bufferFactory) {
super.bufferFactory = bufferFactory;
@@ -17,11 +17,9 @@ package org.springframework.core.io.buffer;
import java.nio.charset.StandardCharsets;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Unit tests for {@link LimitedDataBufferList}.
* @author Rossen Stoyanchev
@@ -31,10 +29,8 @@ public class LimitedDataBufferListTests {
@Test
void limitEnforced() {
LimitedDataBufferList list = new LimitedDataBufferList(5);
assertThatThrownBy(() -> list.add(toDataBuffer("123456"))).isInstanceOf(DataBufferLimitException.class);
assertThat(list).isEmpty();
Assertions.assertThatThrownBy(() -> new LimitedDataBufferList(5).add(toDataBuffer("123456")))
.isInstanceOf(DataBufferLimitException.class);
}
@Test
@@ -130,7 +130,6 @@ class AntPathMatcherTests {
assertThat(pathMatcher.match("", "")).isTrue();
assertThat(pathMatcher.match("/{bla}.*", "/testing.html")).isTrue();
assertThat(pathMatcher.match("/{bla}", "//x\ny")).isTrue();
}
@Test
@@ -26,7 +26,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.testfixture.io.SerializationTestUtils;
import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;
@@ -268,13 +267,13 @@ class MimeTypeTests {
assertThat(mimeType.getParameter("attr")).isEqualTo("'v>alue'");
}
@Test // SPR-16630
@Test // SPR-16630
void parseMimeTypeWithSpacesAroundEquals() {
MimeType mimeType = MimeTypeUtils.parseMimeType("multipart/x-mixed-replace;boundary = --myboundary");
assertThat(mimeType.getParameter("boundary")).isEqualTo("--myboundary");
}
@Test // SPR-16630
@Test // SPR-16630
void parseMimeTypeWithSpacesAroundEqualsAndQuotedValue() {
MimeType mimeType = MimeTypeUtils.parseMimeType("text/plain; foo = \" bar \" ");
assertThat(mimeType.getParameter("foo")).isEqualTo("\" bar \"");
@@ -304,14 +303,14 @@ class MimeTypeTests {
assertThat(mimeTypes.size()).as("Invalid amount of mime types").isEqualTo(0);
}
@Test // gh-23241
@Test // gh-23241
void parseMimeTypesWithTrailingComma() {
List<MimeType> mimeTypes = MimeTypeUtils.parseMimeTypes("text/plain, text/html,");
assertThat(mimeTypes).as("No mime types returned").isNotNull();
assertThat(mimeTypes.size()).as("Incorrect number of mime types").isEqualTo(2);
}
@Test // SPR-17459
@Test // SPR-17459
void parseMimeTypesWithQuotedParameters() {
testWithQuotedParameters("foo/bar;param=\",\"");
testWithQuotedParameters("foo/bar;param=\"s,a,\"");
@@ -333,7 +332,7 @@ class MimeTypeTests {
assertThat(type.getSubtypeSuffix()).isEqualTo("json");
}
@Test // gh-25350
@Test // gh-25350
void wildcardSubtypeCompatibleWithSuffix() {
MimeType applicationStar = new MimeType("application", "*");
MimeType applicationVndJson = new MimeType("application", "vnd.something+json");
@@ -343,9 +342,8 @@ class MimeTypeTests {
private void testWithQuotedParameters(String... mimeTypes) {
String s = String.join(",", mimeTypes);
List<MimeType> actual = MimeTypeUtils.parseMimeTypes(s);
assertThat(actual.size()).isEqualTo(mimeTypes.length);
for (int i = 0; i < mimeTypes.length; i++) {
for (int i=0; i < mimeTypes.length; i++) {
assertThat(actual.get(i).toString()).isEqualTo(mimeTypes[i]);
}
}
@@ -372,7 +370,6 @@ class MimeTypeTests {
List<MimeType> result = new ArrayList<>(expected);
Random rnd = new Random();
// shuffle & sort 10 times
for (int i = 0; i < 10; i++) {
Collections.shuffle(result, rnd);
@@ -402,7 +399,11 @@ class MimeTypeTests {
assertThat(m2.compareTo(m1) != 0).as("Invalid comparison result").isTrue();
}
@Test // SPR-13157
/**
* SPR-13157
* @since 4.2
*/
@Test
void equalsIsCaseInsensitiveForCharsets() {
MimeType m1 = new MimeType("text", "plain", singletonMap("charset", "UTF-8"));
MimeType m2 = new MimeType("text", "plain", singletonMap("charset", "utf-8"));
@@ -412,12 +413,4 @@ class MimeTypeTests {
assertThat(m2.compareTo(m1)).isEqualTo(0);
}
@Test // gh-26127
void serialize() throws Exception {
MimeType original = new MimeType("text", "plain", StandardCharsets.UTF_8);
MimeType deserialized = SerializationTestUtils.serializeAndDeserialize(original);
assertThat(deserialized).isEqualTo(original);
assertThat(original).isEqualTo(deserialized);
}
}
@@ -186,7 +186,12 @@ class ReflectionUtilsTests {
@Test
void doWithProtectedMethods() {
ListSavingMethodCallback mc = new ListSavingMethodCallback();
ReflectionUtils.doWithMethods(TestObject.class, mc, method -> Modifier.isProtected(method.getModifiers()));
ReflectionUtils.doWithMethods(TestObject.class, mc, new ReflectionUtils.MethodFilter() {
@Override
public boolean matches(Method m) {
return Modifier.isProtected(m.getModifiers());
}
});
assertThat(mc.getMethodNames().isEmpty()).isFalse();
assertThat(mc.getMethodNames().contains("clone")).as("Must find protected method on Object").isTrue();
assertThat(mc.getMethodNames().contains("finalize")).as("Must find protected method on Object").isTrue();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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,6 @@
package org.springframework.core.testfixture.io.buffer;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DataBufferWrapper;
import org.springframework.core.io.buffer.PooledDataBuffer;
import org.springframework.util.Assert;
@@ -68,19 +67,19 @@ class LeakAwareDataBuffer extends DataBufferWrapper implements PooledDataBuffer
@Override
public PooledDataBuffer retain() {
DataBufferUtils.retain(dataBuffer());
return this;
}
@Override
public PooledDataBuffer touch(Object hint) {
DataBufferUtils.touch(dataBuffer(), hint);
DataBuffer delegate = dataBuffer();
if (delegate instanceof PooledDataBuffer) {
((PooledDataBuffer) delegate).retain();
}
return this;
}
@Override
public boolean release() {
DataBufferUtils.release(dataBuffer());
DataBuffer delegate = dataBuffer();
if (delegate instanceof PooledDataBuffer) {
((PooledDataBuffer) delegate).release();
}
return isAllocated();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,9 +54,10 @@ public abstract class AstUtils {
}
else {
if (targetType != null) {
int pos = 0;
for (Class<?> clazz : targets) {
if (clazz == targetType) { // put exact matches on the front to be tried first?
specificAccessors.add(resolver);
specificAccessors.add(pos++, resolver);
}
else if (clazz.isAssignableFrom(targetType)) { // put supertype matches at the end of the
// specificAccessor list
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 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.
@@ -63,36 +63,34 @@ import org.springframework.util.StringUtils;
* <p>Individual expressions can be compiled by calling {@code SpelCompiler.compile(expression)}.
*
* @author Andy Clement
* @author Juergen Hoeller
* @since 4.1
*/
public final class SpelCompiler implements Opcodes {
private static final int CLASSES_DEFINED_LIMIT = 100;
private static final Log logger = LogFactory.getLog(SpelCompiler.class);
private static final int CLASSES_DEFINED_LIMIT = 100;
// A compiler is created for each classloader, it manages a child class loader of that
// classloader and the child is used to load the compiled expressions.
private static final Map<ClassLoader, SpelCompiler> compilers = new ConcurrentReferenceHashMap<>();
// The child ClassLoader used to load the compiled expression classes
private volatile ChildClassLoader childClassLoader;
private ChildClassLoader ccl;
// Counter suffix for generated classes within this SpelCompiler instance
private final AtomicInteger suffixId = new AtomicInteger(1);
private SpelCompiler(@Nullable ClassLoader classloader) {
this.childClassLoader = new ChildClassLoader(classloader);
this.ccl = new ChildClassLoader(classloader);
}
/**
* Attempt compilation of the supplied expression. A check is made to see
* if it is compilable before compilation proceeds. The check involves
* visiting all the nodes in the expression AST and ensuring enough state
* visiting all the nodes in the expression Ast and ensuring enough state
* is known about them that bytecode can be generated for them.
* @param expression the expression to compile
* @return an instance of the class implementing the compiled expression,
@@ -127,7 +125,7 @@ public final class SpelCompiler implements Opcodes {
/**
* Generate the class that encapsulates the compiled expression and define it.
* The generated class will be a subtype of CompiledExpression.
* The generated class will be a subtype of CompiledExpression.
* @param expressionToCompile the expression to be compiled
* @return the expression call, or {@code null} if the decision was to opt out of
* compilation during code generation
@@ -137,7 +135,7 @@ public final class SpelCompiler implements Opcodes {
// Create class outline 'spel/ExNNN extends org.springframework.expression.spel.CompiledExpression'
String className = "spel/Ex" + getNextSuffix();
ClassWriter cw = new ExpressionClassWriter();
cw.visit(V1_8, ACC_PUBLIC, className, null, "org/springframework/expression/spel/CompiledExpression", null);
cw.visit(V1_5, ACC_PUBLIC, className, null, "org/springframework/expression/spel/CompiledExpression", null);
// Create default constructor
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
@@ -152,7 +150,7 @@ public final class SpelCompiler implements Opcodes {
// Create getValue() method
mv = cw.visitMethod(ACC_PUBLIC, "getValue",
"(Ljava/lang/Object;Lorg/springframework/expression/EvaluationContext;)Ljava/lang/Object;", null,
new String[] {"org/springframework/expression/EvaluationException"});
new String[ ]{"org/springframework/expression/EvaluationException"});
mv.visitCode();
CodeFlow cf = new CodeFlow(className, cw);
@@ -189,7 +187,7 @@ public final class SpelCompiler implements Opcodes {
/**
* Load a compiled expression class. Makes sure the classloaders aren't used too much
* because they anchor compiled classes in memory and prevent GC. If you have expressions
* because they anchor compiled classes in memory and prevent GC. If you have expressions
* continually recompiling over time then by replacing the classloader periodically
* at least some of the older variants can be garbage collected.
* @param name the name of the class
@@ -198,25 +196,12 @@ public final class SpelCompiler implements Opcodes {
*/
@SuppressWarnings("unchecked")
private Class<? extends CompiledExpression> loadClass(String name, byte[] bytes) {
ChildClassLoader ccl = this.childClassLoader;
if (ccl.getClassesDefinedCount() >= CLASSES_DEFINED_LIMIT) {
synchronized (this) {
ChildClassLoader currentCcl = this.childClassLoader;
if (ccl == currentCcl) {
// Still the same ClassLoader that needs to be replaced...
ccl = new ChildClassLoader(ccl.getParent());
this.childClassLoader = ccl;
}
else {
// Already replaced by some other thread, let's pick it up.
ccl = currentCcl;
}
}
if (this.ccl.getClassesDefinedCount() > CLASSES_DEFINED_LIMIT) {
this.ccl = new ChildClassLoader(this.ccl.getParent());
}
return (Class<? extends CompiledExpression>) ccl.defineClass(name, bytes);
return (Class<? extends CompiledExpression>) this.ccl.defineClass(name, bytes);
}
/**
* Factory method for compiler instances. The returned SpelCompiler will
* attach a class loader as the child of the given class loader and this
@@ -226,28 +211,21 @@ public final class SpelCompiler implements Opcodes {
*/
public static SpelCompiler getCompiler(@Nullable ClassLoader classLoader) {
ClassLoader clToUse = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
// Quick check for existing compiler without lock contention
SpelCompiler compiler = compilers.get(clToUse);
if (compiler == null) {
// Full lock now since we're creating a child ClassLoader
synchronized (compilers) {
compiler = compilers.get(clToUse);
if (compiler == null) {
compiler = new SpelCompiler(clToUse);
compilers.put(clToUse, compiler);
}
synchronized (compilers) {
SpelCompiler compiler = compilers.get(clToUse);
if (compiler == null) {
compiler = new SpelCompiler(clToUse);
compilers.put(clToUse, compiler);
}
return compiler;
}
return compiler;
}
/**
* Request that an attempt is made to compile the specified expression.
* It may fail if components of the expression are not suitable for compilation
* or the data types involved are not suitable for compilation. Used for testing.
* @param expression the expression to compile
* @return {@code true} if the expression was successfully compiled,
* {@code false} otherwise
* Request that an attempt is made to compile the specified expression. It may fail if
* components of the expression are not suitable for compilation or the data types
* involved are not suitable for compilation. Used for testing.
* @return true if the expression was successfully compiled
*/
public static boolean compile(Expression expression) {
return (expression instanceof SpelExpression && ((SpelExpression) expression).compileExpression());
@@ -272,27 +250,24 @@ public final class SpelCompiler implements Opcodes {
private static final URL[] NO_URLS = new URL[0];
private final AtomicInteger classesDefinedCount = new AtomicInteger(0);
private int classesDefinedCount = 0;
public ChildClassLoader(@Nullable ClassLoader classLoader) {
super(NO_URLS, classLoader);
}
public Class<?> defineClass(String name, byte[] bytes) {
Class<?> clazz = super.defineClass(name, bytes, 0, bytes.length);
this.classesDefinedCount.incrementAndGet();
return clazz;
int getClassesDefinedCount() {
return this.classesDefinedCount;
}
public int getClassesDefinedCount() {
return this.classesDefinedCount.get();
public Class<?> defineClass(String name, byte[] bytes) {
Class<?> clazz = super.defineClass(name, bytes, 0, bytes.length);
this.classesDefinedCount++;
return clazz;
}
}
/**
* An ASM ClassWriter extension bound to the SpelCompiler's ClassLoader.
*/
private class ExpressionClassWriter extends ClassWriter {
public ExpressionClassWriter() {
@@ -301,7 +276,7 @@ public final class SpelCompiler implements Opcodes {
@Override
protected ClassLoader getClassLoader() {
return childClassLoader;
return ccl;
}
}
@@ -47,7 +47,7 @@ import org.springframework.util.StringUtils;
/**
* A powerful {@link PropertyAccessor} that uses reflection to access properties
* for reading and possibly also for writing on a target instance.
* for reading and possibly also for writing.
*
* <p>A property can be referenced through a public getter method (when being read)
* or a public setter method (when being written), and also as a public field.
@@ -98,8 +98,8 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
}
/**
* Create a new property accessor for reading and possibly also writing.
* @param allowWrite whether to allow write operations on a target instance
* Create a new property accessor for reading and possibly writing.
* @param allowWrite whether to also allow for write operations
* @since 4.3.15
* @see #canWrite
*/
@@ -395,11 +395,6 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (method == null) {
method = findMethodForProperty(getPropertyMethodSuffixes(propertyName),
"is", clazz, mustBeStatic, 0, BOOLEAN_TYPES);
if (method == null) {
// Record-style plain accessor method, e.g. name()
method = findMethodForProperty(new String[] {propertyName},
"", clazz, mustBeStatic, 0, ANY_TYPES);
}
}
return method;
}
@@ -628,8 +623,8 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
@Override
public String toString() {
return "PropertyCacheKey [clazz=" + this.clazz.getName() + ", property=" + this.property +
", targetIsClass=" + this.targetIsClass + "]";
return "CacheKey [clazz=" + this.clazz.getName() + ", property=" + this.property + ", " +
this.property + ", targetIsClass=" + this.targetIsClass + "]";
}
@Override
@@ -688,11 +683,12 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
return true;
}
getterName = "is" + StringUtils.capitalize(name);
if (getterName.equals(method.getName())) {
return true;
}
return getterName.equals(method.getName());
}
else {
Field field = (Field) this.member;
return field.getName().equals(name);
}
return this.member.getName().equals(name);
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -36,7 +36,6 @@ import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.testresources.Inventor;
import org.springframework.expression.spel.testresources.Person;
import org.springframework.expression.spel.testresources.RecordPerson;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -192,20 +191,6 @@ public class PropertyAccessTests extends AbstractExpressionTests {
parser.parseExpression("name='p3'").getValue(context, target));
}
@Test
public void propertyReadOnlyWithRecordStyle() {
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
Expression expr = parser.parseExpression("name");
RecordPerson target1 = new RecordPerson("p1");
assertThat(expr.getValue(context, target1)).isEqualTo("p1");
RecordPerson target2 = new RecordPerson("p2");
assertThat(expr.getValue(context, target2)).isEqualTo("p2");
assertThatExceptionOfType(SpelEvaluationException.class).isThrownBy(() ->
parser.parseExpression("name='p3'").getValue(context, target2));
}
@Test
public void propertyReadWrite() {
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
@@ -4180,13 +4180,6 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests {
assertThat(expression.getValue(tc)).isEqualTo("value4");
assertCanCompile(expression);
assertThat(expression.getValue(tc)).isEqualTo("value4");
// record-style accessor
expression = parser.parseExpression("strawberry");
assertCantCompile(expression);
assertThat(expression.getValue(tc)).isEqualTo("value5");
assertCanCompile(expression);
assertThat(expression.getValue(tc)).isEqualTo("value5");
}
@Test
@@ -4560,9 +4553,23 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests {
Object v = expression.getValue(ctx,holder);
assertThat(v).isEqualTo("abc");
// // time it interpreted
// long stime = System.currentTimeMillis();
// for (int i = 0; i < 100000; i++) {
// v = expression.getValue(ctx,holder);
// }
// System.out.println((System.currentTimeMillis() - stime));
assertCanCompile(expression);
v = expression.getValue(ctx,holder);
assertThat(v).isEqualTo("abc");
// // time it compiled
// stime = System.currentTimeMillis();
// for (int i = 0; i < 100000; i++) {
// v = expression.getValue(ctx,holder);
// }
// System.out.println((System.currentTimeMillis() - stime));
}
@Test
@@ -4978,12 +4985,13 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests {
assertThat(fast.compileExpression()).isTrue();
r.setValue2(null);
// try the numbers 0,1,2,null
for (int i = 0; i < 4; i++) {
r.setValue(i < 3 ? i : null);
for (int i=0;i<4;i++) {
r.setValue(i<3?i:null);
boolean slowResult = (Boolean)slow.getValue(ctx);
boolean fastResult = (Boolean)fast.getValue(ctx);
assertThat(fastResult).as("Differing results: expression=" + expressionText +
" value=" + r.getValue() + " slow=" + slowResult + " fast="+fastResult).isEqualTo(slowResult);
// System.out.println("Trying "+expressionText+" with value="+r.getValue()+" result is "+slowResult);
assertThat(fastResult).as(" Differing results: expression="+expressionText+
" value="+r.getValue()+" slow="+slowResult+" fast="+fastResult).isEqualTo(slowResult);
}
}
@@ -4994,12 +5002,13 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests {
assertThat(fast.compileExpression()).isTrue();
Reg r = (Reg)ctx.getRootObject().getValue();
// try the numbers 0,1,2,null
for (int i = 0; i < 4; i++) {
r.setValue(i < 3 ? i : null);
for (int i=0;i<4;i++) {
r.setValue(i<3?i:null);
boolean slowResult = (Boolean)slow.getValue(ctx);
boolean fastResult = (Boolean)fast.getValue(ctx);
assertThat(fastResult).as("Differing results: expression=" + expressionText +
" value=" + r.getValue() + " slow=" + slowResult + " fast="+fastResult).isEqualTo(slowResult);
// System.out.println("Trying "+expressionText+" with value="+r.getValue()+" result is "+slowResult);
assertThat(fastResult).as(" Differing results: expression="+expressionText+
" value="+r.getValue()+" slow="+slowResult+" fast="+fastResult).isEqualTo(slowResult);
}
}
@@ -5830,6 +5839,7 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests {
public String orange = "value1";
public static String apple = "value2";
public long peach = 34L;
public String getBanana() {
@@ -5839,10 +5849,6 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests {
public static String getPlum() {
return "value4";
}
public String strawberry() {
return "value5";
}
}
@@ -76,6 +76,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
*/
public class SpelReproTests extends AbstractExpressionTests {
@Test
public void NPE_SPR5661() {
evaluate("joinThreeStrings('a',null,'c')", "anullc", String.class);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -36,10 +36,10 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* @author Andy Clement
* @author Juergen Hoeller
*/
class SpelParserTests {
public class SpelParserTests {
@Test
void theMostBasic() {
public void theMostBasic() {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2");
assertThat(expr).isNotNull();
@@ -50,7 +50,7 @@ class SpelParserTests {
}
@Test
void valueType() {
public void valueType() {
SpelExpressionParser parser = new SpelExpressionParser();
EvaluationContext ctx = new StandardEvaluationContext();
Class<?> c = parser.parseRaw("2").getValueType();
@@ -66,7 +66,7 @@ class SpelParserTests {
}
@Test
void whitespace() {
public void whitespace() {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2 + 3");
assertThat(expr.getValue()).isEqualTo(5);
@@ -79,7 +79,7 @@ class SpelParserTests {
}
@Test
void arithmeticPlus1() {
public void arithmeticPlus1() {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2+2");
assertThat(expr).isNotNull();
@@ -88,65 +88,66 @@ class SpelParserTests {
}
@Test
void arithmeticPlus2() {
public void arithmeticPlus2() {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("37+41");
assertThat(expr.getValue()).isEqualTo(78);
}
@Test
void arithmeticMultiply1() {
public void arithmeticMultiply1() {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2*3");
assertThat(expr).isNotNull();
assertThat(expr.getAST()).isNotNull();
// printAst(expr.getAST(),0);
assertThat(expr.getValue()).isEqualTo(6);
}
@Test
void arithmeticPrecedence1() {
public void arithmeticPrecedence1() {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2*3+5");
assertThat(expr.getValue()).isEqualTo(11);
}
@Test
void generalExpressions() {
public void generalExpressions() {
assertThatExceptionOfType(SpelParseException.class).isThrownBy(() -> {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String");
})
.satisfies(parseExceptionRequirements(SpelMessage.MISSING_CONSTRUCTOR_ARGS, 10));
.satisfies(ex -> parseExceptionRequirements(SpelMessage.MISSING_CONSTRUCTOR_ARGS, 10));
assertThatExceptionOfType(SpelParseException.class).isThrownBy(() -> {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String(3,");
})
.satisfies(parseExceptionRequirements(SpelMessage.RUN_OUT_OF_ARGUMENTS, 10));
.satisfies(ex -> parseExceptionRequirements(SpelMessage.RUN_OUT_OF_ARGUMENTS, 10));
assertThatExceptionOfType(SpelParseException.class).isThrownBy(() -> {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String(3");
})
.satisfies(parseExceptionRequirements(SpelMessage.RUN_OUT_OF_ARGUMENTS, 10));
.satisfies(ex -> parseExceptionRequirements(SpelMessage.RUN_OUT_OF_ARGUMENTS, 10));
assertThatExceptionOfType(SpelParseException.class).isThrownBy(() -> {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String(");
})
.satisfies(parseExceptionRequirements(SpelMessage.RUN_OUT_OF_ARGUMENTS, 10));
.satisfies(ex -> parseExceptionRequirements(SpelMessage.RUN_OUT_OF_ARGUMENTS, 10));
assertThatExceptionOfType(SpelParseException.class).isThrownBy(() -> {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("\"abc");
})
.satisfies(parseExceptionRequirements(SpelMessage.NON_TERMINATING_DOUBLE_QUOTED_STRING, 0));
.satisfies(ex -> parseExceptionRequirements(SpelMessage.NON_TERMINATING_DOUBLE_QUOTED_STRING, 0));
assertThatExceptionOfType(SpelParseException.class).isThrownBy(() -> {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("'abc");
})
.satisfies(parseExceptionRequirements(SpelMessage.NON_TERMINATING_QUOTED_STRING, 0));
.satisfies(ex -> parseExceptionRequirements(SpelMessage.NON_TERMINATING_QUOTED_STRING, 0));
}
@@ -160,38 +161,38 @@ class SpelParserTests {
}
@Test
void arithmeticPrecedence2() {
public void arithmeticPrecedence2() {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2+3*5");
assertThat(expr.getValue()).isEqualTo(17);
}
@Test
void arithmeticPrecedence3() {
public void arithmeticPrecedence3() {
SpelExpression expr = new SpelExpressionParser().parseRaw("3+10/2");
assertThat(expr.getValue()).isEqualTo(8);
}
@Test
void arithmeticPrecedence4() {
public void arithmeticPrecedence4() {
SpelExpression expr = new SpelExpressionParser().parseRaw("10/2+3");
assertThat(expr.getValue()).isEqualTo(8);
}
@Test
void arithmeticPrecedence5() {
public void arithmeticPrecedence5() {
SpelExpression expr = new SpelExpressionParser().parseRaw("(4+10)/2");
assertThat(expr.getValue()).isEqualTo(7);
}
@Test
void arithmeticPrecedence6() {
public void arithmeticPrecedence6() {
SpelExpression expr = new SpelExpressionParser().parseRaw("(3+2)*2");
assertThat(expr.getValue()).isEqualTo(10);
}
@Test
void booleanOperators() {
public void booleanOperators() {
SpelExpression expr = new SpelExpressionParser().parseRaw("true");
assertThat(expr.getValue(Boolean.class)).isEqualTo(Boolean.TRUE);
expr = new SpelExpressionParser().parseRaw("false");
@@ -209,7 +210,7 @@ class SpelParserTests {
}
@Test
void booleanOperators_symbolic_spr9614() {
public void booleanOperators_symbolic_spr9614() {
SpelExpression expr = new SpelExpressionParser().parseRaw("true");
assertThat(expr.getValue(Boolean.class)).isEqualTo(Boolean.TRUE);
expr = new SpelExpressionParser().parseRaw("false");
@@ -227,7 +228,7 @@ class SpelParserTests {
}
@Test
void stringLiterals() {
public void stringLiterals() {
SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'");
assertThat(expr.getValue()).isEqualTo("howdy");
expr = new SpelExpressionParser().parseRaw("'hello '' world'");
@@ -235,13 +236,13 @@ class SpelParserTests {
}
@Test
void stringLiterals2() {
public void stringLiterals2() {
SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'.substring(0,2)");
assertThat(expr.getValue()).isEqualTo("ho");
}
@Test
void testStringLiterals_DoubleQuotes_spr9620() {
public void testStringLiterals_DoubleQuotes_spr9620() {
SpelExpression expr = new SpelExpressionParser().parseRaw("\"double quote: \"\".\"");
assertThat(expr.getValue()).isEqualTo("double quote: \".");
expr = new SpelExpressionParser().parseRaw("\"hello \"\" world\"");
@@ -249,7 +250,7 @@ class SpelParserTests {
}
@Test
void testStringLiterals_DoubleQuotes_spr9620_2() {
public void testStringLiterals_DoubleQuotes_spr9620_2() {
assertThatExceptionOfType(SpelParseException.class).isThrownBy(() ->
new SpelExpressionParser().parseRaw("\"double quote: \\\"\\\".\""))
.satisfies(ex -> {
@@ -259,7 +260,7 @@ class SpelParserTests {
}
@Test
void positionalInformation() {
public void positionalInformation() {
SpelExpression expr = new SpelExpressionParser().parseRaw("true and true or false");
SpelNode rootAst = expr.getAST();
OpOr operatorOr = (OpOr) rootAst;
@@ -288,7 +289,7 @@ class SpelParserTests {
}
@Test
void tokenKind() {
public void tokenKind() {
TokenKind tk = TokenKind.NOT;
assertThat(tk.hasPayload()).isFalse();
assertThat(tk.toString()).isEqualTo("NOT(!)");
@@ -303,7 +304,7 @@ class SpelParserTests {
}
@Test
void token() {
public void token() {
Token token = new Token(TokenKind.NOT, 0, 3);
assertThat(token.kind).isEqualTo(TokenKind.NOT);
assertThat(token.startPos).isEqualTo(0);
@@ -318,7 +319,7 @@ class SpelParserTests {
}
@Test
void exceptions() {
public void exceptions() {
ExpressionException exprEx = new ExpressionException("test");
assertThat(exprEx.getSimpleMessage()).isEqualTo("test");
assertThat(exprEx.toDetailedString()).isEqualTo("test");
@@ -336,13 +337,13 @@ class SpelParserTests {
}
@Test
void parseMethodsOnNumbers() {
public void parseMethodsOnNumbers() {
checkNumber("3.14.toString()", "3.14", String.class);
checkNumber("3.toString()", "3", String.class);
}
@Test
void numerics() {
public void numerics() {
checkNumber("2", 2, Integer.class);
checkNumber("22", 22, Integer.class);
checkNumber("+22", 22, Integer.class);
@@ -384,7 +385,8 @@ class SpelParserTests {
private void checkNumberError(String expression, SpelMessage expectedMessage) {
SpelExpressionParser parser = new SpelExpressionParser();
assertThatExceptionOfType(SpelParseException.class).isThrownBy(() -> parser.parseRaw(expression))
assertThatExceptionOfType(SpelParseException.class).isThrownBy(() ->
parser.parseRaw(expression))
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(expectedMessage));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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,10 +16,9 @@
package org.springframework.expression.spel.testresources;
///CLOVER:OFF
public class Person {
private String privateName;
Company company;
public Person(String name) {
@@ -42,5 +41,4 @@ public class Person {
public Company getCompany() {
return company;
}
}
@@ -1,42 +0,0 @@
/*
* Copyright 2002-2020 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.expression.spel.testresources;
public class RecordPerson {
private String name;
private Company company;
public RecordPerson(String name) {
this.name = name;
}
public RecordPerson(String name, Company company) {
this.name = name;
this.company = company;
}
public String name() {
return name;
}
public Company company() {
return company;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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,25 +19,19 @@ package org.springframework.expression.spel.testresources;
import java.util.List;
public class TestAddress{
private String street;
private List<String> crossStreets;
private String street;
private List<String> crossStreets;
public String getStreet() {
return street;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public List<String> getCrossStreets() {
return crossStreets;
}
public void setCrossStreets(List<String> crossStreets) {
this.crossStreets = crossStreets;
}
}
public void setStreet(String street) {
this.street = street;
}
public List<String> getCrossStreets() {
return crossStreets;
}
public void setCrossStreets(List<String> crossStreets) {
this.crossStreets = crossStreets;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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,25 +17,19 @@
package org.springframework.expression.spel.testresources;
public class TestPerson {
private String name;
private TestAddress address;
private String name;
private TestAddress address;
public String getName() {
return name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public TestAddress getAddress() {
return address;
}
public void setAddress(TestAddress address) {
this.address = address;
}
}
public void setName(String name) {
this.name = name;
}
public TestAddress getAddress() {
return address;
}
public void setAddress(TestAddress address) {
this.address = address;
}
}
@@ -30,6 +30,7 @@ import java.util.Set;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Helper class that efficiently creates multiple {@link PreparedStatementCreator}
@@ -199,8 +200,9 @@ public class PreparedStatementCreatorFactory {
public PreparedStatementCreatorImpl(String actualSql, List<?> parameters) {
this.actualSql = actualSql;
Assert.notNull(parameters, "Parameters List must not be null");
this.parameters = parameters;
if (parameters.size() != declaredParameters.size()) {
if (this.parameters.size() != declaredParameters.size()) {
// Account for named parameters being used multiple times
Set<String> names = new HashSet<>();
for (int i = 0; i < parameters.size(); i++) {
@@ -637,23 +637,21 @@ public class CallMetaDataContext {
schemaNameToUse = this.metaDataProvider.schemaNameToUse(getSchemaName());
}
String procedureNameToUse = this.metaDataProvider.procedureNameToUse(getProcedureName());
if (isFunction() || isReturnValueRequired()) {
callString = new StringBuilder("{? = call ");
callString = new StringBuilder().append("{? = call ").
append(StringUtils.hasLength(catalogNameToUse) ? catalogNameToUse + "." : "").
append(StringUtils.hasLength(schemaNameToUse) ? schemaNameToUse + "." : "").
append(procedureNameToUse).append("(");
parameterCount = -1;
}
else {
callString = new StringBuilder("{call ");
callString = new StringBuilder().append("{call ").
append(StringUtils.hasLength(catalogNameToUse) ? catalogNameToUse + "." : "").
append(StringUtils.hasLength(schemaNameToUse) ? schemaNameToUse + "." : "").
append(procedureNameToUse).append("(");
}
if (StringUtils.hasLength(catalogNameToUse)) {
callString.append(catalogNameToUse).append(".");
}
if (StringUtils.hasLength(schemaNameToUse)) {
callString.append(schemaNameToUse).append(".");
}
callString.append(this.metaDataProvider.procedureNameToUse(getProcedureName()));
callString.append("(");
for (SqlParameter parameter : this.callParameters) {
if (!parameter.isResultsParameter()) {
if (parameterCount > 0) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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.
@@ -83,7 +83,7 @@ public abstract class NamedParameterUtils {
Assert.notNull(sql, "SQL must not be null");
Set<String> namedParameters = new HashSet<>();
StringBuilder sqlToUse = new StringBuilder(sql);
String sqlToUse = sql;
List<ParameterHolder> parameterList = new ArrayList<>();
char[] statement = sql.toCharArray();
@@ -155,7 +155,7 @@ public abstract class NamedParameterUtils {
int j = i + 1;
if (j < statement.length && statement[j] == ':') {
// escaped ":" should be skipped
sqlToUse.deleteCharAt(i - escapes);
sqlToUse = sqlToUse.substring(0, i - escapes) + sqlToUse.substring(i - escapes + 1);
escapes++;
i = i + 2;
continue;
@@ -174,7 +174,7 @@ public abstract class NamedParameterUtils {
}
i++;
}
ParsedSql parsedSql = new ParsedSql(sqlToUse.toString());
ParsedSql parsedSql = new ParsedSql(sqlToUse);
for (ParameterHolder ph : parameterList) {
parsedSql.addNamedParameter(ph.getParameterName(), ph.getStartIndex(), ph.getEndIndex());
}
@@ -345,9 +345,9 @@ public abstract class NamedParameterUtils {
for (int i = 0; i < paramNames.size(); i++) {
String paramName = paramNames.get(i);
try {
Object value = paramSource.getValue(paramName);
SqlParameter param = findParameter(declaredParams, paramName, i);
paramArray[i] = (param != null ? new SqlParameterValue(param, paramSource.getValue(paramName)) :
SqlParameterSourceUtils.getTypedValue(paramSource, paramName));
paramArray[i] = (param != null ? new SqlParameterValue(param, value) : value);
}
catch (IllegalArgumentException ex) {
throw new InvalidDataAccessApiUsageException(
@@ -92,13 +92,17 @@ public abstract class SqlParameterSourceUtils {
* @param source the source of parameter values and type information
* @param parameterName the name of the parameter
* @return the value object
* @see SqlParameterValue
*/
@Nullable
public static Object getTypedValue(SqlParameterSource source, String parameterName) {
int sqlType = source.getSqlType(parameterName);
if (sqlType != SqlParameterSource.TYPE_UNKNOWN) {
return new SqlParameterValue(sqlType, source.getTypeName(parameterName), source.getValue(parameterName));
if (source.getTypeName(parameterName) != null) {
return new SqlParameterValue(sqlType, source.getTypeName(parameterName), source.getValue(parameterName));
}
else {
return new SqlParameterValue(sqlType, source.getValue(parameterName));
}
}
else {
return source.getValue(parameterName);
@@ -561,11 +561,10 @@ public class NamedParameterJdbcTemplateTests {
@Test
public void testBatchUpdateWithSqlParameterSourcePlusTypeInfo() throws Exception {
SqlParameterSource[] ids = new SqlParameterSource[3];
ids[0] = new MapSqlParameterSource().addValue("id", null, Types.NULL);
ids[1] = new MapSqlParameterSource().addValue("id", 100, Types.NUMERIC);
ids[2] = new MapSqlParameterSource().addValue("id", 200, Types.NUMERIC);
final int[] rowsAffected = new int[] {1, 2, 3};
SqlParameterSource[] ids = new SqlParameterSource[2];
ids[0] = new MapSqlParameterSource().addValue("id", 100, Types.NUMERIC);
ids[1] = new MapSqlParameterSource().addValue("id", 200, Types.NUMERIC);
final int[] rowsAffected = new int[] {1, 2};
given(preparedStatement.executeBatch()).willReturn(rowsAffected);
given(connection.getMetaData()).willReturn(databaseMetaData);
@@ -573,15 +572,13 @@ public class NamedParameterJdbcTemplateTests {
int[] actualRowsAffected = namedParameterTemplate.batchUpdate(
"UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
assertThat(actualRowsAffected.length == 3).as("executed 3 updates").isTrue();
assertThat(actualRowsAffected.length == 2).as("executed 2 updates").isTrue();
assertThat(actualRowsAffected[0]).isEqualTo(rowsAffected[0]);
assertThat(actualRowsAffected[1]).isEqualTo(rowsAffected[1]);
assertThat(actualRowsAffected[2]).isEqualTo(rowsAffected[2]);
verify(connection).prepareStatement("UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?");
verify(preparedStatement).setNull(1, Types.NULL);
verify(preparedStatement).setObject(1, 100, Types.NUMERIC);
verify(preparedStatement).setObject(1, 200, Types.NUMERIC);
verify(preparedStatement, times(3)).addBatch();
verify(preparedStatement, times(2)).addBatch();
verify(preparedStatement, atLeastOnce()).close();
verify(connection, atLeastOnce()).close();
}
@@ -94,7 +94,6 @@ public class KotlinSerializationJsonMessageConverter extends AbstractJsonMessage
* Tries to find a serializer that can marshall or unmarshall instances of the given type
* using kotlinx.serialization. If no serializer can be found, an exception is thrown.
* <p>Resolved serializers are cached and cached results are returned on successive calls.
* TODO Avoid relying on throwing exception when https://github.com/Kotlin/kotlinx.serialization/pull/1164 is fixed
* @param type the type to find a serializer for
* @return a resolved serializer for the given type
* @throws RuntimeException if no serializer supporting the given type can be found
@@ -31,8 +31,6 @@ import io.rsocket.Payload;
import io.rsocket.metadata.CompositeMetadata;
import io.rsocket.metadata.RoutingMetadata;
import io.rsocket.metadata.WellKnownMimeType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
@@ -54,9 +52,6 @@ import org.springframework.util.MimeType;
*/
public class DefaultMetadataExtractor implements MetadataExtractor, MetadataExtractorRegistry {
private static final Log logger = LogFactory.getLog(DefaultMetadataExtractor.class);
private final List<Decoder<?>> decoders;
private final Map<String, EntryExtractor<?>> registrations = new HashMap<>();
@@ -124,10 +119,6 @@ public class DefaultMetadataExtractor implements MetadataExtractor, MetadataExtr
else {
extractEntry(payload.metadata().slice(), metadataMimeType.toString(), result);
}
if (logger.isDebugEnabled()) {
logger.debug("Values extracted from metadata: " + result +
" with registrations for " + this.registrations.keySet() + ".");
}
return result;
}
@@ -184,7 +175,7 @@ public class DefaultMetadataExtractor implements MetadataExtractor, MetadataExtr
@Override
public String toString() {
return "\"" + this.mimeType + "\" => " + this.targetType;
return "mimeType=" + this.mimeType + ", targetType=" + this.targetType;
}
}
@@ -71,18 +71,18 @@ import org.springframework.validation.Validator;
* Provides essential configuration for handling messages with simple messaging
* protocols such as STOMP.
*
* <p>{@link #clientInboundChannel(TaskExecutor)} and {@link #clientOutboundChannel(TaskExecutor)} deliver
* <p>{@link #clientInboundChannel()} and {@link #clientOutboundChannel()} deliver
* messages to and from remote clients to several message handlers such as the
* following.
* <ul>
* <li>{@link #simpAnnotationMethodMessageHandler(AbstractSubscribableChannel, AbstractSubscribableChannel, SimpMessagingTemplate, CompositeMessageConverter)}</li>
* <li>{@link #simpleBrokerMessageHandler(AbstractSubscribableChannel, AbstractSubscribableChannel, AbstractSubscribableChannel, UserDestinationResolver)}</li>
* <li>{@link #stompBrokerRelayMessageHandler(AbstractSubscribableChannel, AbstractSubscribableChannel, AbstractSubscribableChannel, UserDestinationMessageHandler, MessageHandler, UserDestinationResolver)}</li>
* <li>{@link #userDestinationMessageHandler(AbstractSubscribableChannel, AbstractSubscribableChannel, AbstractSubscribableChannel, UserDestinationResolver)}</li>
* <li>{@link #simpAnnotationMethodMessageHandler()}</li>
* <li>{@link #simpleBrokerMessageHandler()}</li>
* <li>{@link #stompBrokerRelayMessageHandler()}</li>
* <li>{@link #userDestinationMessageHandler()}</li>
* </ul>
*
* <p>{@link #brokerChannel(AbstractSubscribableChannel, AbstractSubscribableChannel, TaskExecutor)} delivers messages from within the application to the
* the respective message handlers. {@link #brokerMessagingTemplate(AbstractSubscribableChannel, AbstractSubscribableChannel, AbstractSubscribableChannel, CompositeMessageConverter)} can be injected
* <p>{@link #brokerChannel()} delivers messages from within the application to the
* the respective message handlers. {@link #brokerMessagingTemplate()} can be injected
* into any application component to send messages.
*
* <p>Subclasses are responsible for the parts of the configuration that feed messages
@@ -90,7 +90,6 @@ import org.springframework.validation.Validator;
*
* @author Rossen Stoyanchev
* @author Brian Clozel
* @author Sebastien Deleuze
* @since 4.0
*/
public abstract class AbstractMessageBrokerConfiguration implements ApplicationContextAware {
@@ -148,8 +147,8 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
@Bean
public AbstractSubscribableChannel clientInboundChannel(TaskExecutor clientInboundChannelExecutor) {
ExecutorSubscribableChannel channel = new ExecutorSubscribableChannel(clientInboundChannelExecutor);
public AbstractSubscribableChannel clientInboundChannel() {
ExecutorSubscribableChannel channel = new ExecutorSubscribableChannel(clientInboundChannelExecutor());
channel.setLogger(SimpLogging.forLog(channel.getLogger()));
ChannelRegistration reg = getClientInboundChannelRegistration();
if (reg.hasInterceptors()) {
@@ -184,8 +183,8 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
}
@Bean
public AbstractSubscribableChannel clientOutboundChannel(TaskExecutor clientOutboundChannelExecutor) {
ExecutorSubscribableChannel channel = new ExecutorSubscribableChannel(clientOutboundChannelExecutor);
public AbstractSubscribableChannel clientOutboundChannel() {
ExecutorSubscribableChannel channel = new ExecutorSubscribableChannel(clientOutboundChannelExecutor());
channel.setLogger(SimpLogging.forLog(channel.getLogger()));
ChannelRegistration reg = getClientOutboundChannelRegistration();
if (reg.hasInterceptors()) {
@@ -220,11 +219,10 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
}
@Bean
public AbstractSubscribableChannel brokerChannel(AbstractSubscribableChannel clientInboundChannel,
AbstractSubscribableChannel clientOutboundChannel, TaskExecutor brokerChannelExecutor) {
ChannelRegistration reg = getBrokerRegistry(clientInboundChannel, clientOutboundChannel).getBrokerChannelRegistration();
public AbstractSubscribableChannel brokerChannel() {
ChannelRegistration reg = getBrokerRegistry().getBrokerChannelRegistration();
ExecutorSubscribableChannel channel = (reg.hasTaskExecutor() ?
new ExecutorSubscribableChannel(brokerChannelExecutor) : new ExecutorSubscribableChannel());
new ExecutorSubscribableChannel(brokerChannelExecutor()) : new ExecutorSubscribableChannel());
reg.interceptors(new ImmutableMessageChannelInterceptor());
channel.setLogger(SimpLogging.forLog(channel.getLogger()));
channel.setInterceptors(reg.getInterceptors());
@@ -232,9 +230,8 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
}
@Bean
public TaskExecutor brokerChannelExecutor(AbstractSubscribableChannel clientInboundChannel,
AbstractSubscribableChannel clientOutboundChannel) {
ChannelRegistration reg = getBrokerRegistry(clientInboundChannel, clientOutboundChannel).getBrokerChannelRegistration();
public TaskExecutor brokerChannelExecutor() {
ChannelRegistration reg = getBrokerRegistry().getBrokerChannelRegistration();
ThreadPoolTaskExecutor executor;
if (reg.hasTaskExecutor()) {
executor = reg.taskExecutor().getTaskExecutor();
@@ -254,10 +251,9 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
* An accessor for the {@link MessageBrokerRegistry} that ensures its one-time creation
* and initialization through {@link #configureMessageBroker(MessageBrokerRegistry)}.
*/
protected final MessageBrokerRegistry getBrokerRegistry(AbstractSubscribableChannel clientInboundChannel,
AbstractSubscribableChannel clientOutboundChannel) {
protected final MessageBrokerRegistry getBrokerRegistry() {
if (this.brokerRegistry == null) {
MessageBrokerRegistry registry = new MessageBrokerRegistry(clientInboundChannel, clientOutboundChannel);
MessageBrokerRegistry registry = new MessageBrokerRegistry(clientInboundChannel(), clientOutboundChannel());
configureMessageBroker(registry);
this.brokerRegistry = registry;
}
@@ -276,20 +272,15 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
* configuration classes.
*/
@Nullable
public final PathMatcher getPathMatcher(AbstractSubscribableChannel clientInboundChannel,
AbstractSubscribableChannel clientOutboundChannel) {
return getBrokerRegistry(clientInboundChannel, clientOutboundChannel).getPathMatcher();
public final PathMatcher getPathMatcher() {
return getBrokerRegistry().getPathMatcher();
}
@Bean
public SimpAnnotationMethodMessageHandler simpAnnotationMethodMessageHandler(
AbstractSubscribableChannel clientInboundChannel, AbstractSubscribableChannel clientOutboundChannel,
SimpMessagingTemplate brokerMessagingTemplate, CompositeMessageConverter brokerMessageConverter) {
SimpAnnotationMethodMessageHandler handler = createAnnotationMethodMessageHandler(clientInboundChannel,
clientOutboundChannel, brokerMessagingTemplate);
MessageBrokerRegistry brokerRegistry = getBrokerRegistry(clientInboundChannel, clientOutboundChannel);
handler.setDestinationPrefixes(brokerRegistry.getApplicationDestinationPrefixes());
handler.setMessageConverter(brokerMessageConverter);
public SimpAnnotationMethodMessageHandler simpAnnotationMethodMessageHandler() {
SimpAnnotationMethodMessageHandler handler = createAnnotationMethodMessageHandler();
handler.setDestinationPrefixes(getBrokerRegistry().getApplicationDestinationPrefixes());
handler.setMessageConverter(brokerMessageConverter());
handler.setValidator(simpValidator());
List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();
@@ -300,7 +291,7 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
addReturnValueHandlers(returnValueHandlers);
handler.setCustomReturnValueHandlers(returnValueHandlers);
PathMatcher pathMatcher = brokerRegistry.getPathMatcher();
PathMatcher pathMatcher = getBrokerRegistry().getPathMatcher();
if (pathMatcher != null) {
handler.setPathMatcher(pathMatcher);
}
@@ -311,12 +302,11 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
* Protected method for plugging in a custom subclass of
* {@link org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler
* SimpAnnotationMethodMessageHandler}.
* @since 5.3.2
* @since 4.2
*/
protected SimpAnnotationMethodMessageHandler createAnnotationMethodMessageHandler(
AbstractSubscribableChannel clientInboundChannel, AbstractSubscribableChannel clientOutboundChannel,
SimpMessagingTemplate brokerMessagingTemplate) {
return new SimpAnnotationMethodMessageHandler(clientInboundChannel, clientOutboundChannel, brokerMessagingTemplate);
protected SimpAnnotationMethodMessageHandler createAnnotationMethodMessageHandler() {
return new SimpAnnotationMethodMessageHandler(clientInboundChannel(),
clientOutboundChannel(), brokerMessagingTemplate());
}
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
@@ -327,56 +317,48 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
@Bean
@Nullable
public AbstractBrokerMessageHandler simpleBrokerMessageHandler(AbstractSubscribableChannel clientInboundChannel,
AbstractSubscribableChannel clientOutboundChannel, AbstractSubscribableChannel brokerChannel,
UserDestinationResolver userDestinationResolver) {
SimpleBrokerMessageHandler handler = getBrokerRegistry(clientInboundChannel, clientOutboundChannel).getSimpleBroker(brokerChannel);
public AbstractBrokerMessageHandler simpleBrokerMessageHandler() {
SimpleBrokerMessageHandler handler = getBrokerRegistry().getSimpleBroker(brokerChannel());
if (handler == null) {
return null;
}
updateUserDestinationResolver(handler, userDestinationResolver);
updateUserDestinationResolver(handler);
return handler;
}
private void updateUserDestinationResolver(AbstractBrokerMessageHandler handler, UserDestinationResolver userDestinationResolver) {
private void updateUserDestinationResolver(AbstractBrokerMessageHandler handler) {
Collection<String> prefixes = handler.getDestinationPrefixes();
if (!prefixes.isEmpty() && !prefixes.iterator().next().startsWith("/")) {
((DefaultUserDestinationResolver) userDestinationResolver).setRemoveLeadingSlash(true);
((DefaultUserDestinationResolver) userDestinationResolver()).setRemoveLeadingSlash(true);
}
}
@Bean
@Nullable
public AbstractBrokerMessageHandler stompBrokerRelayMessageHandler(AbstractSubscribableChannel clientInboundChannel,
AbstractSubscribableChannel clientOutboundChannel, AbstractSubscribableChannel brokerChannel,
UserDestinationMessageHandler userDestinationMessageHandler, @Nullable MessageHandler userRegistryMessageHandler,
UserDestinationResolver userDestinationResolver) {
MessageBrokerRegistry brokerRegistry = getBrokerRegistry(clientInboundChannel, clientOutboundChannel);
StompBrokerRelayMessageHandler handler = brokerRegistry.getStompBrokerRelay(brokerChannel);
public AbstractBrokerMessageHandler stompBrokerRelayMessageHandler() {
StompBrokerRelayMessageHandler handler = getBrokerRegistry().getStompBrokerRelay(brokerChannel());
if (handler == null) {
return null;
}
Map<String, MessageHandler> subscriptions = new HashMap<>(4);
String destination = brokerRegistry.getUserDestinationBroadcast();
String destination = getBrokerRegistry().getUserDestinationBroadcast();
if (destination != null) {
subscriptions.put(destination, userDestinationMessageHandler);
subscriptions.put(destination, userDestinationMessageHandler());
}
destination = brokerRegistry.getUserRegistryBroadcast();
destination = getBrokerRegistry().getUserRegistryBroadcast();
if (destination != null) {
subscriptions.put(destination, userRegistryMessageHandler);
subscriptions.put(destination, userRegistryMessageHandler());
}
handler.setSystemSubscriptions(subscriptions);
updateUserDestinationResolver(handler, userDestinationResolver);
updateUserDestinationResolver(handler);
return handler;
}
@Bean
public UserDestinationMessageHandler userDestinationMessageHandler(AbstractSubscribableChannel clientInboundChannel,
AbstractSubscribableChannel clientOutboundChannel, AbstractSubscribableChannel brokerChannel,
UserDestinationResolver userDestinationResolver) {
UserDestinationMessageHandler handler = new UserDestinationMessageHandler(clientInboundChannel,
brokerChannel, userDestinationResolver);
String destination = getBrokerRegistry(clientInboundChannel, clientOutboundChannel).getUserDestinationBroadcast();
public UserDestinationMessageHandler userDestinationMessageHandler() {
UserDestinationMessageHandler handler = new UserDestinationMessageHandler(clientInboundChannel(),
brokerChannel(), userDestinationResolver());
String destination = getBrokerRegistry().getUserDestinationBroadcast();
if (destination != null) {
handler.setBroadcastDestination(destination);
}
@@ -385,17 +367,15 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
@Bean
@Nullable
public MessageHandler userRegistryMessageHandler(AbstractSubscribableChannel clientInboundChannel,
AbstractSubscribableChannel clientOutboundChannel, SimpUserRegistry userRegistry,
SimpMessagingTemplate brokerMessagingTemplate, TaskScheduler messageBrokerTaskScheduler) {
MessageBrokerRegistry brokerRegistry = getBrokerRegistry(clientInboundChannel, clientOutboundChannel);
if (brokerRegistry.getUserRegistryBroadcast() == null) {
public MessageHandler userRegistryMessageHandler() {
if (getBrokerRegistry().getUserRegistryBroadcast() == null) {
return null;
}
SimpUserRegistry userRegistry = userRegistry();
Assert.isInstanceOf(MultiServerUserRegistry.class, userRegistry, "MultiServerUserRegistry required");
return new UserRegistryMessageHandler((MultiServerUserRegistry) userRegistry,
brokerMessagingTemplate, brokerRegistry.getUserRegistryBroadcast(),
messageBrokerTaskScheduler);
brokerMessagingTemplate(), getBrokerRegistry().getUserRegistryBroadcast(),
messageBrokerTaskScheduler());
}
// Expose alias for 4.1 compatibility
@@ -409,15 +389,13 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
}
@Bean
public SimpMessagingTemplate brokerMessagingTemplate(AbstractSubscribableChannel brokerChannel,
AbstractSubscribableChannel clientInboundChannel, AbstractSubscribableChannel clientOutboundChannel,
CompositeMessageConverter brokerMessageConverter) {
SimpMessagingTemplate template = new SimpMessagingTemplate(brokerChannel);
String prefix = getBrokerRegistry(clientInboundChannel, clientOutboundChannel).getUserDestinationPrefix();
public SimpMessagingTemplate brokerMessagingTemplate() {
SimpMessagingTemplate template = new SimpMessagingTemplate(brokerChannel());
String prefix = getBrokerRegistry().getUserDestinationPrefix();
if (prefix != null) {
template.setUserDestinationPrefix(prefix);
}
template.setMessageConverter(brokerMessageConverter);
template.setMessageConverter(brokerMessageConverter());
return template;
}
@@ -463,10 +441,9 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
}
@Bean
public UserDestinationResolver userDestinationResolver(SimpUserRegistry userRegistry,
AbstractSubscribableChannel clientInboundChannel, AbstractSubscribableChannel clientOutboundChannel) {
DefaultUserDestinationResolver resolver = new DefaultUserDestinationResolver(userRegistry);
String prefix = getBrokerRegistry(clientInboundChannel, clientOutboundChannel).getUserDestinationPrefix();
public UserDestinationResolver userDestinationResolver() {
DefaultUserDestinationResolver resolver = new DefaultUserDestinationResolver(userRegistry());
String prefix = getBrokerRegistry().getUserDestinationPrefix();
if (prefix != null) {
resolver.setUserDestinationPrefix(prefix);
}
@@ -475,14 +452,12 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
@Bean
@SuppressWarnings("deprecation")
public SimpUserRegistry userRegistry(AbstractSubscribableChannel clientInboundChannel,
AbstractSubscribableChannel clientOutboundChannel) {
public SimpUserRegistry userRegistry() {
SimpUserRegistry registry = createLocalUserRegistry();
MessageBrokerRegistry brokerRegistry = getBrokerRegistry(clientInboundChannel, clientOutboundChannel);
if (registry == null) {
registry = createLocalUserRegistry(brokerRegistry.getUserRegistryOrder());
registry = createLocalUserRegistry(getBrokerRegistry().getUserRegistryOrder());
}
boolean broadcast = brokerRegistry.getUserRegistryBroadcast() != null;
boolean broadcast = getBrokerRegistry().getUserRegistryBroadcast() != null;
return (broadcast ? new MultiServerUserRegistry(registry) : registry);
}
@@ -56,9 +56,6 @@ public class StompBrokerRelayRegistration extends AbstractBrokerRegistration {
@Nullable
private TcpOperations<byte[]> tcpClient;
@Nullable
private TaskScheduler taskScheduler;
private boolean autoStartup = true;
@Nullable
@@ -67,6 +64,8 @@ public class StompBrokerRelayRegistration extends AbstractBrokerRegistration {
@Nullable
private String userRegistryBroadcast;
@Nullable
private TaskScheduler taskScheduler;
public StompBrokerRelayRegistration(SubscribableChannel clientInboundChannel,
MessageChannel clientOutboundChannel, String[] destinationPrefixes) {
@@ -182,27 +181,8 @@ public class StompBrokerRelayRegistration extends AbstractBrokerRegistration {
* specified are effectively ignored.
* @since 4.3.15
*/
public StompBrokerRelayRegistration setTcpClient(TcpOperations<byte[]> tcpClient) {
public void setTcpClient(TcpOperations<byte[]> tcpClient) {
this.tcpClient = tcpClient;
return this;
}
/**
* Some STOMP clients (e.g. stomp-js) always send heartbeats at a fixed rate
* but others (Spring STOMP client) do so only when no other messages are
* sent. However messages with a non-broker {@link #getDestinationPrefixes()
* destination prefix} aren't forwarded and as a result the broker may deem
* the connection inactive.
* <p>When this {@link TaskScheduler} is set, it is used to reset a count of
* the number of messages sent from client to broker since the beginning of
* the current heartbeat period. This is then used to decide whether to send
* a heartbeat to the broker when ignoring a message with a non-broker
* destination prefix.
* @since 5.3
*/
public StompBrokerRelayRegistration setTaskScheduler(@Nullable TaskScheduler taskScheduler) {
this.taskScheduler = taskScheduler;
return this;
}
/**
@@ -248,6 +228,26 @@ public class StompBrokerRelayRegistration extends AbstractBrokerRegistration {
return this;
}
/**
* Some STOMP clients (e.g. stomp-js) always send heartbeats at a fixed rate
* but others (Spring STOMP client) do so only when no other messages are
* sent. However messages with a non-broker {@link #getDestinationPrefixes()
* destination prefix} aren't forwarded and as a result the broker may deem
* the connection inactive.
*
* <p>When this {@link TaskScheduler} is set, it is used to reset a count of
* the number of messages sent from client to broker since the beginning of
* the current heartbeat period. This is then used to decide whether to send
* a heartbeat to the broker when ignoring a message with a non-broker
* destination prefix.
*
* @param taskScheduler the scheduler to use
* @since 5.3
*/
public void setTaskScheduler(@Nullable TaskScheduler taskScheduler) {
this.taskScheduler = taskScheduler;
}
@Nullable
protected String getUserRegistryBroadcast() {
return this.userRegistryBroadcast;
@@ -256,6 +256,7 @@ public class StompBrokerRelayRegistration extends AbstractBrokerRegistration {
@Override
protected StompBrokerRelayMessageHandler getMessageHandler(SubscribableChannel brokerChannel) {
StompBrokerRelayMessageHandler handler = new StompBrokerRelayMessageHandler(
getClientInboundChannel(), getClientOutboundChannel(),
brokerChannel, getDestinationPrefixes());
@@ -378,14 +378,13 @@ public class MessageHeaderAccessor {
* {@link #copyHeadersIfAbsent(Map)} to avoid overwriting values.
*/
public void copyHeaders(@Nullable Map<String, ?> headersToCopy) {
if (headersToCopy == null || this.headers == headersToCopy) {
return;
if (headersToCopy != null) {
headersToCopy.forEach((key, value) -> {
if (!isReadOnly(key)) {
setHeader(key, value);
}
});
}
headersToCopy.forEach((key, value) -> {
if (!isReadOnly(key)) {
setHeader(key, value);
}
});
}
/**
@@ -393,14 +392,13 @@ public class MessageHeaderAccessor {
* <p>This operation will <em>not</em> overwrite any existing values.
*/
public void copyHeadersIfAbsent(@Nullable Map<String, ?> headersToCopy) {
if (headersToCopy == null || this.headers == headersToCopy) {
return;
if (headersToCopy != null) {
headersToCopy.forEach((key, value) -> {
if (!isReadOnly(key)) {
setHeaderIfAbsent(key, value);
}
});
}
headersToCopy.forEach((key, value) -> {
if (!isReadOnly(key)) {
setHeaderIfAbsent(key, value);
}
});
}
protected boolean isReadOnly(String headerName) {
@@ -75,8 +75,6 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
@SuppressWarnings("unchecked")
Map<String, List<String>> map = (Map<String, List<String>>) getHeader(NATIVE_HEADERS);
if (map != null) {
// setHeader checks for equality but we need copy of native headers
setHeader(NATIVE_HEADERS, null);
setHeader(NATIVE_HEADERS, new LinkedMultiValueMap<>(map));
}
}
@@ -105,8 +103,6 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
if (isMutable()) {
Map<String, List<String>> map = getNativeHeaders();
if (map != null) {
// setHeader checks for equality but we need immutable wrapper
setHeader(NATIVE_HEADERS, null);
setHeader(NATIVE_HEADERS, Collections.unmodifiableMap(map));
}
super.setImmutable();
@@ -114,34 +110,31 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
}
@Override
public void copyHeaders(@Nullable Map<String, ?> headersToCopy) {
if (headersToCopy == null) {
return;
public void setHeader(String name, @Nullable Object value) {
if (name.equalsIgnoreCase(NATIVE_HEADERS)) {
// Force removal since setHeader checks for equality
super.setHeader(NATIVE_HEADERS, null);
}
@SuppressWarnings("unchecked")
Map<String, List<String>> map = (Map<String, List<String>>) headersToCopy.get(NATIVE_HEADERS);
if (map != null && map != getNativeHeaders()) {
map.forEach(this::setNativeHeaderValues);
}
// setHeader checks for equality, native headers should be equal by now
super.copyHeaders(headersToCopy);
super.setHeader(name, value);
}
@Override
public void copyHeadersIfAbsent(@Nullable Map<String, ?> headersToCopy) {
if (headersToCopy == null) {
return;
@SuppressWarnings("unchecked")
public void copyHeaders(@Nullable Map<String, ?> headersToCopy) {
if (headersToCopy != null) {
Map<String, List<String>> nativeHeaders = getNativeHeaders();
Map<String, List<String>> map = (Map<String, List<String>>) headersToCopy.get(NATIVE_HEADERS);
if (map != null) {
if (nativeHeaders != null) {
nativeHeaders.putAll(map);
}
else {
nativeHeaders = new LinkedMultiValueMap<>(map);
}
}
super.copyHeaders(headersToCopy);
setHeader(NATIVE_HEADERS, nativeHeaders);
}
@SuppressWarnings("unchecked")
Map<String, List<String>> map = (Map<String, List<String>>) headersToCopy.get(NATIVE_HEADERS);
if (map != null && getNativeHeaders() == null) {
map.forEach(this::setNativeHeaderValues);
}
super.copyHeadersIfAbsent(headersToCopy);
}
/**
@@ -208,30 +201,6 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
}
}
/**
* Variant of {@link #addNativeHeader(String, String)} for all values.
* @since 5.2.12
*/
public void setNativeHeaderValues(String name, @Nullable List<String> values) {
Assert.state(isMutable(), "Already immutable");
Map<String, List<String>> map = getNativeHeaders();
if (values == null) {
if (map != null && map.get(name) != null) {
setModified(true);
map.remove(name);
}
return;
}
if (map == null) {
map = new LinkedMultiValueMap<>(3);
setHeader(NATIVE_HEADERS, map);
}
if (!ObjectUtils.nullSafeEquals(values, getHeader(name))) {
setModified(true);
map.put(name, new ArrayList<>(values));
}
}
/**
* Add the specified native header value to existing values.
* <p>In order for this to work, the accessor must be {@link #isMutable()
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-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,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.task.TaskExecutor;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
@@ -595,20 +594,19 @@ public class MessageBrokerConfigurationTests {
@Override
@Bean
public AbstractSubscribableChannel clientInboundChannel(TaskExecutor clientInboundChannelExecutor) {
public AbstractSubscribableChannel clientInboundChannel() {
return new TestChannel();
}
@Override
@Bean
public AbstractSubscribableChannel clientOutboundChannel(TaskExecutor clientOutboundChannelExecutor) {
public AbstractSubscribableChannel clientOutboundChannel() {
return new TestChannel();
}
@Override
@Bean
public AbstractSubscribableChannel brokerChannel(AbstractSubscribableChannel clientInboundChannel,
AbstractSubscribableChannel clientOutboundChannel, TaskExecutor brokerChannelExecutor) {
public AbstractSubscribableChannel brokerChannel() {
return new TestChannel();
}
}
@@ -682,21 +680,20 @@ public class MessageBrokerConfigurationTests {
@Override
@Bean
public AbstractSubscribableChannel clientInboundChannel(TaskExecutor clientInboundChannelExecutor) {
public AbstractSubscribableChannel clientInboundChannel() {
// synchronous
return new ExecutorSubscribableChannel(null);
}
@Override
@Bean
public AbstractSubscribableChannel clientOutboundChannel(TaskExecutor clientOutboundChannelExecutor) {
public AbstractSubscribableChannel clientOutboundChannel() {
return new TestChannel();
}
@Override
@Bean
public AbstractSubscribableChannel brokerChannel(AbstractSubscribableChannel clientInboundChannel,
AbstractSubscribableChannel clientOutboundChannel, TaskExecutor brokerChannelExecutor) {
public AbstractSubscribableChannel brokerChannel() {
// synchronous
return new ExecutorSubscribableChannel(null);
}
@@ -226,46 +226,19 @@ public class NativeMessageHeaderAccessorTests {
@Test // gh-25821
void copyImmutableToMutable() {
NativeMessageHeaderAccessor sourceAccessor = new NativeMessageHeaderAccessor();
sourceAccessor.addNativeHeader("foo", "bar");
Message<String> source = MessageBuilder.createMessage("payload", sourceAccessor.getMessageHeaders());
NativeMessageHeaderAccessor source = new NativeMessageHeaderAccessor();
source.addNativeHeader("foo", "bar");
Message<String> message = MessageBuilder.createMessage("payload", source.getMessageHeaders());
NativeMessageHeaderAccessor targetAccessor = new NativeMessageHeaderAccessor();
targetAccessor.copyHeaders(source.getHeaders());
targetAccessor.setLeaveMutable(true);
Message<?> target = MessageBuilder.createMessage(source.getPayload(), targetAccessor.getMessageHeaders());
NativeMessageHeaderAccessor target = new NativeMessageHeaderAccessor();
target.copyHeaders(message.getHeaders());
target.setLeaveMutable(true);
message = MessageBuilder.createMessage(message.getPayload(), target.getMessageHeaders());
MessageHeaderAccessor accessor = MessageHeaderAccessor.getMutableAccessor(target);
MessageHeaderAccessor accessor = MessageHeaderAccessor.getMutableAccessor(message);
assertThat(accessor.isMutable());
((NativeMessageHeaderAccessor) accessor).addNativeHeader("foo", "baz");
assertThat(((NativeMessageHeaderAccessor) accessor).getNativeHeader("foo")).containsExactly("bar", "baz");
}
@Test // gh-25821
void copyIfAbsentImmutableToMutable() {
NativeMessageHeaderAccessor sourceAccessor = new NativeMessageHeaderAccessor();
sourceAccessor.addNativeHeader("foo", "bar");
Message<String> source = MessageBuilder.createMessage("payload", sourceAccessor.getMessageHeaders());
MessageHeaderAccessor targetAccessor = new NativeMessageHeaderAccessor();
targetAccessor.copyHeadersIfAbsent(source.getHeaders());
targetAccessor.setLeaveMutable(true);
Message<?> target = MessageBuilder.createMessage(source.getPayload(), targetAccessor.getMessageHeaders());
MessageHeaderAccessor accessor = MessageHeaderAccessor.getMutableAccessor(target);
assertThat(accessor.isMutable());
((NativeMessageHeaderAccessor) accessor).addNativeHeader("foo", "baz");
assertThat(((NativeMessageHeaderAccessor) accessor).getNativeHeader("foo")).containsExactly("bar", "baz");
}
@Test // gh-26155
void copySelf() {
NativeMessageHeaderAccessor accessor = new NativeMessageHeaderAccessor();
accessor.addNativeHeader("foo", "bar");
accessor.setHeader("otherHeader", "otherHeaderValue");
accessor.setLeaveMutable(true);
// Does not fail with ConcurrentModificationException
accessor.copyHeaders(accessor.getMessageHeaders());
}
}
@@ -418,13 +418,10 @@ public abstract class AbstractEntityManagerFactoryBean implements
String message = ex.getMessage();
String causeString = cause.toString();
if (!message.endsWith(causeString)) {
ex = new PersistenceException(message + "; nested exception is " + causeString, cause);
throw new PersistenceException(message + "; nested exception is " + causeString, cause);
}
}
}
if (logger.isErrorEnabled()) {
logger.error("Failed to initialize JPA EntityManagerFactory: " + ex.getMessage());
}
throw ex;
}
@@ -48,9 +48,9 @@ import org.springframework.lang.Nullable;
* EntityManager. Developed and tested against Hibernate 5.3 and 5.4;
* backwards-compatible with Hibernate 5.2 at runtime on a best-effort basis.
*
* <p>Exposes Hibernate's persistence provider and Hibernate's Session as extended
* EntityManager interface, and adapts {@link AbstractJpaVendorAdapter}'s common
* configuration settings. Also supports the detection of annotated packages (through
* <p>Exposes Hibernate's persistence provider and EntityManager extension interface,
* and adapts {@link AbstractJpaVendorAdapter}'s common configuration settings.
* Also supports the detection of annotated packages (through
* {@link org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo#getManagedPackages()}),
* e.g. containing Hibernate {@link org.hibernate.annotations.FilterDef} annotations,
* along with Spring-driven entity scanning which requires no {@code persistence.xml}
@@ -82,8 +82,8 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
public HibernateJpaVendorAdapter() {
this.persistenceProvider = new SpringHibernateJpaPersistenceProvider();
this.entityManagerFactoryInterface = SessionFactory.class; // as of Spring 5.3
this.entityManagerInterface = Session.class; // as of Spring 5.3
this.entityManagerFactoryInterface = SessionFactory.class;
this.entityManagerInterface = Session.class;
}
@@ -95,7 +95,7 @@ abstract class NamedParameterUtils {
Assert.notNull(sql, "SQL must not be null");
Set<String> namedParameters = new HashSet<>();
StringBuilder sqlToUse = new StringBuilder(sql);
String sqlToUse = sql;
List<ParameterHolder> parameterList = new ArrayList<>();
char[] statement = sql.toCharArray();
@@ -171,7 +171,8 @@ abstract class NamedParameterUtils {
int j = i + 1;
if (j < statement.length && statement[j] == ':') {
// escaped ":" should be skipped
sqlToUse.deleteCharAt(i - escapes);
sqlToUse = sqlToUse.substring(0, i - escapes)
+ sqlToUse.substring(i - escapes + 1);
escapes++;
i = i + 2;
continue;
@@ -180,7 +181,7 @@ abstract class NamedParameterUtils {
}
i++;
}
ParsedSql parsedSql = new ParsedSql(sqlToUse.toString());
ParsedSql parsedSql = new ParsedSql(sqlToUse);
for (ParameterHolder ph : parameterList) {
parsedSql.addNamedParameter(ph.getParameterName(), ph.getStartIndex(), ph.getEndIndex());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@@ -83,7 +83,7 @@ public @interface ActiveProfiles {
* <p>The default value is {@code true}, which means that a test
* class will <em>inherit</em> bean definition profiles defined by a
* test superclass. Specifically, the bean definition profiles for a test
* class will be appended to the list of bean definition profiles
* class will be added to the list of bean definition profiles
* defined by a test superclass. Thus, subclasses have the option of
* <em>extending</em> the list of bean definition profiles.
* <p>If {@code inheritProfiles} is set to {@code false}, the bean
@@ -41,11 +41,6 @@ import java.lang.annotation.Target;
* is resolved. Typically, method references are used to supply values, as in the
* example below.
*
* <p>As of Spring Framework 5.3.2, dynamic properties from methods annotated with
* {@code @DynamicPropertySource} will be <em>inherited</em> from enclosing test
* classes, analogous to inheritance from superclasses and interfaces. See
* {@link NestedTestConfiguration @NestedTestConfiguration} for details.
*
* <p><strong>NOTE</strong>: if you use {@code @DynamicPropertySource} in a base
* class and discover that tests in subclasses fail because the dynamic properties
* change between subclasses, you may need to annotate your base class with
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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,8 +19,8 @@ package org.springframework.test.context;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
@@ -533,8 +533,8 @@ public class MergedContextConfiguration implements Serializable {
return EMPTY_STRING_ARRAY;
}
// Active profiles must be unique
Set<String> profilesSet = new LinkedHashSet<>(Arrays.asList(activeProfiles));
// Active profiles must be unique and sorted
Set<String> profilesSet = new TreeSet<>(Arrays.asList(activeProfiles));
return StringUtils.toStringArray(profilesSet);
}
@@ -74,7 +74,6 @@ import org.springframework.lang.Nullable;
* <li>{@link org.springframework.test.context.web.WebAppConfiguration @WebAppConfiguration}</li>
* <li>{@link ActiveProfiles @ActiveProfiles}</li>
* <li>{@link TestPropertySource @TestPropertySource}</li>
* <li>{@link DynamicPropertySource @DynamicPropertySource}</li>
* <li>{@link org.springframework.test.annotation.DirtiesContext @DirtiesContext}</li>
* <li>{@link org.springframework.transaction.annotation.Transactional @Transactional}</li>
* <li>{@link org.springframework.test.annotation.Rollback @Rollback}</li>
@@ -492,11 +492,10 @@ public abstract class TestContextAnnotationUtils {
Assert.notNull(annotation, "Annotation must not be null");
this.rootDeclaringClass = rootDeclaringClass;
this.declaringClass = declaringClass;
T mergedAnnotation = (T) AnnotatedElementUtils.findMergedAnnotation(
this.annotation = (T) AnnotatedElementUtils.findMergedAnnotation(
rootDeclaringClass, annotation.annotationType());
Assert.state(mergedAnnotation != null,
Assert.state(this.annotation != null,
() -> "Failed to find merged annotation for " + annotation);
this.annotation = mergedAnnotation;
}
public Class<?> getRootDeclaringClass() {
@@ -546,13 +545,15 @@ public abstract class TestContextAnnotationUtils {
/**
* Find <strong>all</strong> annotations of the specified annotation type
* that are present or meta-present on the {@linkplain #getRootDeclaringClass()
* root declaring class} of this descriptor or on any interfaces that the
* root declaring class implements.
* root declaring class} of this descriptor.
* @return the set of all merged, synthesized {@code Annotations} found,
* or an empty set if none were found
*/
public Set<T> findAllLocalMergedAnnotations() {
SearchStrategy searchStrategy = SearchStrategy.TYPE_HIERARCHY;
SearchStrategy searchStrategy =
(getEnclosingConfiguration(getRootDeclaringClass()) == EnclosingConfiguration.INHERIT ?
SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES :
SearchStrategy.TYPE_HIERARCHY);
return MergedAnnotations.from(getRootDeclaringClass(), searchStrategy, RepeatableContainers.none())
.stream(getAnnotationType())
.filter(MergedAnnotationPredicates.firstRunOf(MergedAnnotation::getAggregateIndex))
@@ -16,19 +16,11 @@
package org.springframework.test.context.junit.jupiter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
@@ -41,22 +33,15 @@ import org.junit.jupiter.api.extension.ExtensionContext.Store;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.junit.jupiter.api.extension.TestInstancePostProcessor;
import org.junit.platform.commons.annotation.Testable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.ParameterResolutionDelegate;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.core.annotation.RepeatableContainers;
import org.springframework.lang.Nullable;
import org.springframework.test.context.TestConstructor;
import org.springframework.test.context.TestContextManager;
import org.springframework.test.context.support.PropertyProvider;
import org.springframework.test.context.support.TestConstructorUtils;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.MethodFilter;
/**
* {@code SpringExtension} integrates the <em>Spring TestContext Framework</em>
@@ -79,29 +64,10 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes
ParameterResolver {
/**
* {@link Namespace} in which {@code TestContextManagers} are stored, keyed
* by test class.
* {@link Namespace} in which {@code TestContextManagers} are stored,
* keyed by test class.
*/
private static final Namespace TEST_CONTEXT_MANAGER_NAMESPACE = Namespace.create(SpringExtension.class);
/**
* {@link Namespace} in which {@code @Autowired} validation error messages
* are stored, keyed by test class.
*/
private static final Namespace AUTOWIRED_VALIDATION_NAMESPACE = Namespace.create(SpringExtension.class.getName() +
"#autowired.validation");
private static final String NO_AUTOWIRED_VIOLATIONS_DETECTED = "NO AUTOWIRED VIOLATIONS DETECTED";
// Note that @Test, @TestFactory, @TestTemplate, @RepeatedTest, and @ParameterizedTest
// are all meta-annotated with @Testable.
private static final List<Class<? extends Annotation>> JUPITER_ANNOTATION_TYPES =
Arrays.asList(BeforeAll.class, AfterAll.class, BeforeEach.class, AfterEach.class, Testable.class);
private static final MethodFilter autowiredTestOrLifecycleMethodFilter =
ReflectionUtils.USER_DECLARED_METHODS
.and(method -> !Modifier.isPrivate(method.getModifiers()))
.and(SpringExtension::isAutowiredTestOrLifecycleMethod);
private static final Namespace NAMESPACE = Namespace.create(SpringExtension.class);
/**
@@ -127,42 +93,12 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes
/**
* Delegates to {@link TestContextManager#prepareTestInstance}.
* <p>As of Spring Framework 5.3.2, this method also validates that test
* methods and test lifecycle methods are not annotated with
* {@link Autowired @Autowired}.
*/
@Override
public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception {
validateAutowiredConfig(context);
getTestContextManager(context).prepareTestInstance(testInstance);
}
/**
* Validate that test methods and test lifecycle methods in the supplied
* test class are not annotated with {@link Autowired @Autowired}.
* @since 5.3.2
*/
private void validateAutowiredConfig(ExtensionContext context) {
// We save the result in the ExtensionContext.Store so that we don't
// re-validate all methods for the same test class multiple times.
Store store = context.getStore(AUTOWIRED_VALIDATION_NAMESPACE);
String errorMessage = store.getOrComputeIfAbsent(context.getRequiredTestClass(),
testClass -> {
Method[] methodsWithErrors =
ReflectionUtils.getUniqueDeclaredMethods(testClass, autowiredTestOrLifecycleMethodFilter);
return (methodsWithErrors.length == 0 ? NO_AUTOWIRED_VIOLATIONS_DETECTED :
String.format(
"Test methods and test lifecycle methods must not be annotated with @Autowired. " +
"You should instead annotate individual method parameters with @Autowired, " +
"@Qualifier, or @Value. Offending methods in test class %s: %s",
testClass.getName(), Arrays.toString(methodsWithErrors)));
}, String.class);
if (errorMessage != NO_AUTOWIRED_VIOLATIONS_DETECTED) {
throw new IllegalStateException(errorMessage);
}
}
/**
* Delegates to {@link TestContextManager#beforeTestMethod}.
*/
@@ -283,21 +219,7 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes
}
private static Store getStore(ExtensionContext context) {
return context.getRoot().getStore(TEST_CONTEXT_MANAGER_NAMESPACE);
}
private static boolean isAutowiredTestOrLifecycleMethod(Method method) {
MergedAnnotations mergedAnnotations =
MergedAnnotations.from(method, SearchStrategy.DIRECT, RepeatableContainers.none());
if (!mergedAnnotations.isPresent(Autowired.class)) {
return false;
}
for (Class<? extends Annotation> annotationType : JUPITER_ANNOTATION_TYPES) {
if (mergedAnnotations.isPresent(annotationType)) {
return true;
}
}
return false;
return context.getRoot().getStore(NAMESPACE);
}
}
@@ -16,10 +16,8 @@
package org.springframework.test.context.support;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -72,8 +70,8 @@ abstract class ActiveProfilesUtils {
static String[] resolveActiveProfiles(Class<?> testClass) {
Assert.notNull(testClass, "Class must not be null");
Set<String> activeProfiles = new TreeSet<>();
AnnotationDescriptor<ActiveProfiles> descriptor = findAnnotationDescriptor(testClass, ActiveProfiles.class);
List<String[]> profileArrays = new ArrayList<>();
if (descriptor == null && logger.isDebugEnabled()) {
logger.debug(String.format(
@@ -109,24 +107,16 @@ abstract class ActiveProfilesUtils {
String[] profiles = resolver.resolve(rootDeclaringClass);
if (!ObjectUtils.isEmpty(profiles)) {
// Prepend to the list so that we can later traverse "down" the hierarchy
// to ensure that we retain the top-down profile registration order
// within a test class hierarchy.
profileArrays.add(0, profiles);
for (String profile : profiles) {
if (StringUtils.hasText(profile)) {
activeProfiles.add(profile.trim());
}
}
}
descriptor = (annotation.inheritProfiles() ? descriptor.next() : null);
}
Set<String> activeProfiles = new LinkedHashSet<>();
for (String[] profiles : profileArrays) {
for (String profile : profiles) {
if (StringUtils.hasText(profile)) {
activeProfiles.add(profile.trim());
}
}
}
return StringUtils.toStringArray(activeProfiles);
}
@@ -17,7 +17,6 @@
package org.springframework.test.context.support;
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -27,14 +26,12 @@ import org.springframework.lang.Nullable;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizerFactory;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.test.context.TestContextAnnotationUtils;
/**
* {@link ContextCustomizerFactory} to support
* {@link DynamicPropertySource @DynamicPropertySource} methods.
*
* @author Phillip Webb
* @author Sam Brannen
* @since 5.2.5
* @see DynamicPropertiesContextCustomizer
*/
@@ -45,21 +42,13 @@ class DynamicPropertiesContextCustomizerFactory implements ContextCustomizerFact
public DynamicPropertiesContextCustomizer createContextCustomizer(Class<?> testClass,
List<ContextConfigurationAttributes> configAttributes) {
Set<Method> methods = new LinkedHashSet<>();
findMethods(testClass, methods);
Set<Method> methods = MethodIntrospector.selectMethods(testClass, this::isAnnotated);
if (methods.isEmpty()) {
return null;
}
return new DynamicPropertiesContextCustomizer(methods);
}
private void findMethods(Class<?> testClass, Set<Method> methods) {
methods.addAll(MethodIntrospector.selectMethods(testClass, this::isAnnotated));
if (TestContextAnnotationUtils.searchEnclosingClass(testClass)) {
findMethods(testClass.getEnclosingClass(), methods);
}
}
private boolean isAnnotated(Method method) {
return MergedAnnotations.from(method).isPresent(DynamicPropertySource.class);
}

Some files were not shown because too many files have changed in this diff Show More