Compare commits

..

1 Commits

Author SHA1 Message Date
Spring Builds 5ea8ba1b96 Release v5.3.23 2022-09-15 07:47:35 +00:00
151 changed files with 832 additions and 2112 deletions
@@ -9,5 +9,5 @@ jobs:
name: "Validation"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1
-1
View File
@@ -24,7 +24,6 @@ buildSrc/build
/spring-core/graalvm/build
/spring-core/kotlin-coroutines/build
/framework-bom/build
/framework-docs/build
/integration-tests/build
/src/asciidoc/build
target/
+1 -1
View File
@@ -1,3 +1,3 @@
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=8.0.352-librca
java=8.0.345-librca
+23 -26
View File
@@ -1,17 +1,17 @@
plugins {
id 'io.spring.dependency-management' version '1.0.11.RELEASE' apply false
id 'io.spring.nohttp' version '0.0.10'
id 'io.freefair.aspectj' version '6.2.0' apply false
id "io.freefair.aspectj" version '6.2.0' apply false
id 'org.jetbrains.dokka' version '1.6.10' apply false
id 'org.jetbrains.kotlin.jvm' version '1.5.32' apply false
id 'org.jetbrains.kotlin.plugin.serialization' version "1.5.32" apply false
id "org.jetbrains.kotlin.plugin.serialization" version "1.5.32" apply false
id 'org.asciidoctor.jvm.convert' version '3.3.2'
id 'org.asciidoctor.jvm.pdf' version '3.3.2'
id 'org.unbroken-dome.xjc' version '2.0.0' apply false
id 'com.github.ben-manes.versions' version '0.39.0'
id 'com.github.johnrengelman.shadow' version '7.0.0' apply false
id "org.unbroken-dome.xjc" version '2.0.0' apply false
id "com.github.ben-manes.versions" version '0.39.0'
id "com.github.johnrengelman.shadow" version '7.0.0' apply false
id 'de.undercouch.download' version '4.1.2'
id 'me.champeau.jmh' version "0.6.6" apply false
id "me.champeau.jmh" version "0.6.6" apply false
}
ext {
@@ -28,18 +28,18 @@ configure(allprojects) { project ->
dependencyManagement {
imports {
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.7"
mavenBom "io.netty:netty-bom:4.1.85.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.25"
mavenBom "io.netty:netty-bom:4.1.82.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.23"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR13"
mavenBom "io.rsocket:rsocket-bom:1.1.3"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.49.v20220914"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.48.v20220622"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.5.32"
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.5.2"
mavenBom "org.jetbrains.kotlinx:kotlinx-serialization-bom:1.2.2"
mavenBom "org.junit:junit-bom:5.8.2"
}
dependencies {
dependencySet(group: 'org.apache.logging.log4j', version: '2.19.0') {
dependencySet(group: 'org.apache.logging.log4j', version: '2.18.0') {
entry 'log4j-api'
entry 'log4j-core'
entry 'log4j-jul'
@@ -68,7 +68,7 @@ configure(allprojects) { project ->
dependency "io.reactivex:rxjava-reactive-streams:1.2.1"
dependency "io.reactivex.rxjava2:rxjava:2.2.21"
dependency "io.reactivex.rxjava3:rxjava:3.1.5"
dependency "io.smallrye.reactive:mutiny:1.8.0"
dependency "io.smallrye.reactive:mutiny:1.7.0"
dependency "io.projectreactor.tools:blockhound:1.0.6.RELEASE"
dependency "com.caucho:hessian:4.0.63"
@@ -96,7 +96,7 @@ configure(allprojects) { project ->
dependency "com.h2database:h2:2.1.214"
dependency "com.github.ben-manes.caffeine:caffeine:2.9.3"
dependency "com.github.librepdf:openpdf:1.3.30"
dependency "com.github.librepdf:openpdf:1.3.29"
dependency "com.rometools:rome:1.18.0"
dependency "commons-io:commons-io:2.5"
dependency "io.vavr:vavr:0.10.4"
@@ -128,18 +128,18 @@ configure(allprojects) { project ->
dependency "org.webjars:webjars-locator-core:0.48"
dependency "org.webjars:underscorejs:1.8.3"
dependencySet(group: 'org.apache.tomcat', version: '9.0.68') {
dependencySet(group: 'org.apache.tomcat', version: '9.0.65') {
entry 'tomcat-util'
entry('tomcat-websocket') {
exclude group: "org.apache.tomcat", name: "tomcat-servlet-api"
exclude group: "org.apache.tomcat", name: "tomcat-websocket-api"
}
}
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.68') {
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.65') {
entry 'tomcat-embed-core'
entry 'tomcat-embed-websocket'
}
dependencySet(group: 'io.undertow', version: '2.2.21.Final') {
dependencySet(group: 'io.undertow', version: '2.2.19.Final') {
entry 'undertow-core'
entry('undertow-servlet') {
exclude group: "org.jboss.spec.javax.servlet", name: "jboss-servlet-api_4.0_spec"
@@ -150,7 +150,7 @@ configure(allprojects) { project ->
}
}
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.13"
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.12"
dependency 'org.apache.httpcomponents.client5:httpclient5:5.1.3'
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.1.3'
dependency("org.apache.httpcomponents:httpclient:4.5.13") {
@@ -198,7 +198,7 @@ configure(allprojects) { project ->
exclude group: "org.hamcrest", name: "hamcrest-core"
}
}
dependencySet(group: 'org.mockito', version: '4.8.1') {
dependencySet(group: 'org.mockito', version: '4.6.1') {
entry('mockito-core') {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
@@ -206,10 +206,10 @@ configure(allprojects) { project ->
}
dependency "io.mockk:mockk:1.12.1"
dependency("net.sourceforge.htmlunit:htmlunit:2.66.0") {
dependency("net.sourceforge.htmlunit:htmlunit:2.64.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:htmlunit-driver:2.66.0") {
dependency("org.seleniumhq.selenium:htmlunit-driver:2.64.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
@@ -340,7 +340,7 @@ configure([rootProject] + javaProjects) { project ->
}
checkstyle {
toolVersion = "10.4"
toolVersion = "10.3.3"
configDirectory.set(rootProject.file("src/checkstyle"))
}
@@ -413,9 +413,11 @@ configure(rootProject) {
nohttp {
source.exclude "**/test-output/**"
source.exclude "spring-core/graalvm/build/**" // only available on `main`
source.exclude "spring-core-test/build/**" // only available on `main`
allowlistFile = project.file("src/nohttp/allowlist.lines")
def rootPath = file(rootDir).toPath()
def projectDirs = allprojects.collect { it.projectDir } + "${rootDir}/spring-core-test" + "${rootDir}/buildSrc" + "${rootDir}/framework-docs"
def projectDirs = allprojects.collect { it.projectDir } + "${rootDir}/buildSrc"
projectDirs.forEach { dir ->
[ 'bin', 'build', 'out', '.settings' ]
.collect { rootPath.relativize(new File(dir, it).toPath()) }
@@ -426,10 +428,6 @@ configure(rootProject) {
}
}
tasks.named("checkstyleNohttp").configure {
maxHeapSize = "1g"
}
publishing {
publications {
mavenJava(MavenPublication) {
@@ -439,5 +437,4 @@ configure(rootProject) {
}
}
}
}
-3
View File
@@ -15,6 +15,3 @@ changelog:
sort: "title"
labels:
- "type: dependency-upgrade"
contributors:
exclude:
names: ["bclozel", "jhoeller", "poutsma", "rstoyanchev", "sbrannen", "sdeleuze", "snicoll"]
+1 -1
View File
@@ -1,4 +1,4 @@
FROM ubuntu:focal-20220922
FROM ubuntu:focal-20220826
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
+1 -1
View File
@@ -1,4 +1,4 @@
version=5.3.24
version=5.3.23
org.gradle.jvmargs=-Xmx2048m
org.gradle.caching=true
org.gradle.parallel=true
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
+2 -2
View File
@@ -7,8 +7,8 @@ pluginManagement {
}
plugins {
id "com.gradle.enterprise" version "3.11.1"
id "io.spring.ge.conventions" version "0.0.11"
id "com.gradle.enterprise" version "3.10.2"
id "io.spring.ge.conventions" version "0.0.10"
}
include "spring-aop"
@@ -97,6 +97,8 @@ public final class CachedIntrospectionResults {
*/
public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore";
private static final PropertyDescriptor[] EMPTY_PROPERTY_DESCRIPTOR_ARRAY = {};
private static final boolean shouldIntrospectorIgnoreBeaninfoClasses =
SpringProperties.getFlag(IGNORE_BEANINFO_PROPERTY_NAME);
@@ -295,7 +297,7 @@ public final class CachedIntrospectionResults {
// Only allow URL attribute introspection, not content resolution
continue;
}
if (pd.getWriteMethod() == null && isInvalidReadOnlyPropertyType(pd.getPropertyType(), beanClass)) {
if (pd.getWriteMethod() == null && isInvalidReadOnlyPropertyType(pd.getPropertyType())) {
// Ignore read-only properties such as ClassLoader - no need to bind to those
continue;
}
@@ -345,8 +347,7 @@ public final class CachedIntrospectionResults {
// GenericTypeAwarePropertyDescriptor leniently resolves a set* write method
// against a declared read method, so we prefer read method descriptors here.
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
if (pd.getWriteMethod() == null &&
isInvalidReadOnlyPropertyType(pd.getPropertyType(), beanClass)) {
if (pd.getWriteMethod() == null && isInvalidReadOnlyPropertyType(pd.getPropertyType())) {
// Ignore read-only properties such as ClassLoader - no need to bind to those
continue;
}
@@ -379,7 +380,7 @@ public final class CachedIntrospectionResults {
if (Modifier.isStatic(method.getModifiers()) ||
method.getDeclaringClass() == Object.class || method.getDeclaringClass() == Class.class ||
method.getParameterCount() > 0 || method.getReturnType() == void.class ||
isInvalidReadOnlyPropertyType(method.getReturnType(), method.getDeclaringClass())) {
isInvalidReadOnlyPropertyType(method.getReturnType())) {
return false;
}
try {
@@ -392,11 +393,10 @@ public final class CachedIntrospectionResults {
}
}
private boolean isInvalidReadOnlyPropertyType(@Nullable Class<?> returnType, Class<?> beanClass) {
return (returnType != null && (ClassLoader.class.isAssignableFrom(returnType) ||
ProtectionDomain.class.isAssignableFrom(returnType) ||
(AutoCloseable.class.isAssignableFrom(returnType) &&
!AutoCloseable.class.isAssignableFrom(beanClass))));
private boolean isInvalidReadOnlyPropertyType(@Nullable Class<?> returnType) {
return (returnType != null && (AutoCloseable.class.isAssignableFrom(returnType) ||
ClassLoader.class.isAssignableFrom(returnType) ||
ProtectionDomain.class.isAssignableFrom(returnType)));
}
@@ -422,7 +422,7 @@ public final class CachedIntrospectionResults {
}
PropertyDescriptor[] getPropertyDescriptors() {
return this.propertyDescriptors.values().toArray(PropertyDescriptorUtils.EMPTY_PROPERTY_DESCRIPTOR_ARRAY);
return this.propertyDescriptors.values().toArray(EMPTY_PROPERTY_DESCRIPTOR_ARRAY);
}
private PropertyDescriptor buildGenericTypeAwarePropertyDescriptor(Class<?> beanClass, PropertyDescriptor pd) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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,15 +17,9 @@
package org.springframework.beans;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
@@ -38,80 +32,6 @@ import org.springframework.util.ObjectUtils;
*/
abstract class PropertyDescriptorUtils {
public static final PropertyDescriptor[] EMPTY_PROPERTY_DESCRIPTOR_ARRAY = {};
/**
* Simple introspection algorithm for basic set/get/is accessor methods,
* building corresponding JavaBeans property descriptors for them.
* <p>This just supports the basic JavaBeans conventions, without indexed
* properties or any customizers, and without other BeanInfo metadata.
* For standard JavaBeans introspection, use the JavaBeans Introspector.
* @param beanClass the target class to introspect
* @return a collection of property descriptors
* @throws IntrospectionException from introspecting the given bean class
* @since 5.3.24
* @see SimpleBeanInfoFactory
* @see java.beans.Introspector#getBeanInfo(Class)
*/
public static Collection<? extends PropertyDescriptor> determineBasicProperties(Class<?> beanClass)
throws IntrospectionException {
Map<String, BasicPropertyDescriptor> pdMap = new TreeMap<>();
for (Method method : beanClass.getMethods()) {
String methodName = method.getName();
boolean setter;
int nameIndex;
if (methodName.startsWith("set") && method.getParameterCount() == 1) {
setter = true;
nameIndex = 3;
}
else if (methodName.startsWith("get") && method.getParameterCount() == 0 && method.getReturnType() != Void.TYPE) {
setter = false;
nameIndex = 3;
}
else if (methodName.startsWith("is") && method.getParameterCount() == 0 && method.getReturnType() == boolean.class) {
setter = false;
nameIndex = 2;
}
else {
continue;
}
String propertyName = Introspector.decapitalize(methodName.substring(nameIndex));
if (propertyName.isEmpty()) {
continue;
}
BasicPropertyDescriptor pd = pdMap.get(propertyName);
if (pd != null) {
if (setter) {
if (pd.getWriteMethod() == null ||
pd.getWriteMethod().getParameterTypes()[0].isAssignableFrom(method.getParameterTypes()[0])) {
pd.setWriteMethod(method);
}
else {
pd.addWriteMethod(method);
}
}
else {
if (pd.getReadMethod() == null ||
(pd.getReadMethod().getReturnType() == method.getReturnType() && method.getName().startsWith("is"))) {
pd.setReadMethod(method);
}
}
}
else {
pd = new BasicPropertyDescriptor(propertyName, (!setter ? method : null), (setter ? method : null));
pdMap.put(propertyName, pd);
}
}
return pdMap.values();
}
/**
* See {@link java.beans.FeatureDescriptor}.
*/
@@ -253,72 +173,4 @@ abstract class PropertyDescriptorUtils {
pd.isBound() == otherPd.isBound() && pd.isConstrained() == otherPd.isConstrained());
}
/**
* PropertyDescriptor for {@link #determineBasicProperties(Class)},
* not performing any early type determination for
* {@link #setReadMethod}/{@link #setWriteMethod}.
* @since 5.3.24
*/
private static class BasicPropertyDescriptor extends PropertyDescriptor {
@Nullable
private Method readMethod;
@Nullable
private Method writeMethod;
private final List<Method> alternativeWriteMethods = new ArrayList<>();
public BasicPropertyDescriptor(String propertyName, @Nullable Method readMethod, @Nullable Method writeMethod)
throws IntrospectionException {
super(propertyName, readMethod, writeMethod);
}
@Override
public void setReadMethod(@Nullable Method readMethod) {
this.readMethod = readMethod;
}
@Override
@Nullable
public Method getReadMethod() {
return this.readMethod;
}
@Override
public void setWriteMethod(@Nullable Method writeMethod) {
this.writeMethod = writeMethod;
}
public void addWriteMethod(Method writeMethod) {
if (this.writeMethod != null) {
this.alternativeWriteMethods.add(this.writeMethod);
this.writeMethod = null;
}
this.alternativeWriteMethods.add(writeMethod);
}
@Override
@Nullable
public Method getWriteMethod() {
if (this.writeMethod == null && !this.alternativeWriteMethods.isEmpty()) {
if (this.readMethod == null) {
return this.alternativeWriteMethods.get(0);
}
else {
for (Method method : this.alternativeWriteMethods) {
if (this.readMethod.getReturnType().isAssignableFrom(method.getParameterTypes()[0])) {
this.writeMethod = method;
break;
}
}
}
}
return this.writeMethod;
}
}
}
@@ -1,66 +0,0 @@
/*
* Copyright 2002-2022 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.beans;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.beans.SimpleBeanInfo;
import java.util.Collection;
import org.springframework.core.Ordered;
import org.springframework.lang.NonNull;
/**
* {@link BeanInfoFactory} implementation that bypasses the standard {@link java.beans.Introspector}
* for faster introspection, reduced to basic property determination (as commonly needed in Spring).
*
* <p>To be configured via a {@code META-INF/spring.factories} file with the following content,
* overriding other custom {@code org.springframework.beans.BeanInfoFactory} declarations:
* {@code org.springframework.beans.BeanInfoFactory=org.springframework.beans.SimpleBeanInfoFactory}
*
* <p>Ordered at {@code Ordered.LOWEST_PRECEDENCE - 1} to override {@link ExtendedBeanInfoFactory}
* (registered by default in 5.3) if necessary while still allowing other user-defined
* {@link BeanInfoFactory} types to take precedence.
*
* @author Juergen Hoeller
* @since 5.3.24
* @see ExtendedBeanInfoFactory
* @see CachedIntrospectionResults
*/
public class SimpleBeanInfoFactory implements BeanInfoFactory, Ordered {
@Override
@NonNull
public BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException {
Collection<? extends PropertyDescriptor> pds =
PropertyDescriptorUtils.determineBasicProperties(beanClass);
return new SimpleBeanInfo() {
@Override
public PropertyDescriptor[] getPropertyDescriptors() {
return pds.toArray(PropertyDescriptorUtils.EMPTY_PROPERTY_DESCRIPTOR_ARRAY);
}
};
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 1;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -438,6 +438,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
}
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
@@ -562,9 +563,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
* @param type the type of the bean
* @return the target beans, or an empty Collection if no bean of this type is found
* @throws BeansException if bean retrieval failed
* @deprecated since 5.3.24 since it is unused in the meantime
*/
@Deprecated
protected <T> Map<String, T> findAutowireCandidates(Class<T> type) throws BeansException {
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory configured - " +
@@ -161,7 +161,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
/** Cache of pre-filtered post-processors. */
@Nullable
private BeanPostProcessorCache beanPostProcessorCache;
private volatile BeanPostProcessorCache beanPostProcessorCache;
/** Map from scope identifier String to corresponding Scope. */
private final Map<String, Scope> scopes = new LinkedHashMap<>(8);
@@ -944,12 +944,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
synchronized (this.beanPostProcessors) {
// Remove from old position, if any
this.beanPostProcessors.remove(beanPostProcessor);
// Add to end of list
this.beanPostProcessors.add(beanPostProcessor);
}
// Remove from old position, if any
this.beanPostProcessors.remove(beanPostProcessor);
// Add to end of list
this.beanPostProcessors.add(beanPostProcessor);
}
/**
@@ -959,12 +957,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
* @see #addBeanPostProcessor
*/
public void addBeanPostProcessors(Collection<? extends BeanPostProcessor> beanPostProcessors) {
synchronized (this.beanPostProcessors) {
// Remove from old position, if any
this.beanPostProcessors.removeAll(beanPostProcessors);
// Add to end of list
this.beanPostProcessors.addAll(beanPostProcessors);
}
this.beanPostProcessors.removeAll(beanPostProcessors);
this.beanPostProcessors.addAll(beanPostProcessors);
}
@Override
@@ -986,34 +980,26 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
* @since 5.3
*/
BeanPostProcessorCache getBeanPostProcessorCache() {
synchronized (this.beanPostProcessors) {
BeanPostProcessorCache bppCache = this.beanPostProcessorCache;
if (bppCache == null) {
bppCache = new BeanPostProcessorCache();
for (BeanPostProcessor bpp : this.beanPostProcessors) {
if (bpp instanceof InstantiationAwareBeanPostProcessor) {
bppCache.instantiationAware.add((InstantiationAwareBeanPostProcessor) bpp);
if (bpp instanceof SmartInstantiationAwareBeanPostProcessor) {
bppCache.smartInstantiationAware.add((SmartInstantiationAwareBeanPostProcessor) bpp);
}
}
if (bpp instanceof DestructionAwareBeanPostProcessor) {
bppCache.destructionAware.add((DestructionAwareBeanPostProcessor) bpp);
}
if (bpp instanceof MergedBeanDefinitionPostProcessor) {
bppCache.mergedDefinition.add((MergedBeanDefinitionPostProcessor) bpp);
BeanPostProcessorCache bpCache = this.beanPostProcessorCache;
if (bpCache == null) {
bpCache = new BeanPostProcessorCache();
for (BeanPostProcessor bp : this.beanPostProcessors) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
bpCache.instantiationAware.add((InstantiationAwareBeanPostProcessor) bp);
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
bpCache.smartInstantiationAware.add((SmartInstantiationAwareBeanPostProcessor) bp);
}
}
this.beanPostProcessorCache = bppCache;
if (bp instanceof DestructionAwareBeanPostProcessor) {
bpCache.destructionAware.add((DestructionAwareBeanPostProcessor) bp);
}
if (bp instanceof MergedBeanDefinitionPostProcessor) {
bpCache.mergedDefinition.add((MergedBeanDefinitionPostProcessor) bp);
}
}
return bppCache;
}
}
private void resetBeanPostProcessorCache() {
synchronized (this.beanPostProcessors) {
this.beanPostProcessorCache = null;
this.beanPostProcessorCache = bpCache;
}
return bpCache;
}
/**
@@ -2028,27 +2014,27 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
@Override
public BeanPostProcessor set(int index, BeanPostProcessor element) {
BeanPostProcessor result = super.set(index, element);
resetBeanPostProcessorCache();
beanPostProcessorCache = null;
return result;
}
@Override
public boolean add(BeanPostProcessor o) {
boolean success = super.add(o);
resetBeanPostProcessorCache();
beanPostProcessorCache = null;
return success;
}
@Override
public void add(int index, BeanPostProcessor element) {
super.add(index, element);
resetBeanPostProcessorCache();
beanPostProcessorCache = null;
}
@Override
public BeanPostProcessor remove(int index) {
BeanPostProcessor result = super.remove(index);
resetBeanPostProcessorCache();
beanPostProcessorCache = null;
return result;
}
@@ -2056,7 +2042,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
public boolean remove(Object o) {
boolean success = super.remove(o);
if (success) {
resetBeanPostProcessorCache();
beanPostProcessorCache = null;
}
return success;
}
@@ -2065,7 +2051,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
public boolean removeAll(Collection<?> c) {
boolean success = super.removeAll(c);
if (success) {
resetBeanPostProcessorCache();
beanPostProcessorCache = null;
}
return success;
}
@@ -2074,7 +2060,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
public boolean retainAll(Collection<?> c) {
boolean success = super.retainAll(c);
if (success) {
resetBeanPostProcessorCache();
beanPostProcessorCache = null;
}
return success;
}
@@ -2083,7 +2069,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
public boolean addAll(Collection<? extends BeanPostProcessor> c) {
boolean success = super.addAll(c);
if (success) {
resetBeanPostProcessorCache();
beanPostProcessorCache = null;
}
return success;
}
@@ -2092,7 +2078,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
public boolean addAll(int index, Collection<? extends BeanPostProcessor> c) {
boolean success = super.addAll(index, c);
if (success) {
resetBeanPostProcessorCache();
beanPostProcessorCache = null;
}
return success;
}
@@ -2101,7 +2087,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
public boolean removeIf(Predicate<? super BeanPostProcessor> filter) {
boolean success = super.removeIf(filter);
if (success) {
resetBeanPostProcessorCache();
beanPostProcessorCache = null;
}
return success;
}
@@ -2109,7 +2095,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
@Override
public void replaceAll(UnaryOperator<BeanPostProcessor> operator) {
super.replaceAll(operator);
resetBeanPostProcessorCache();
beanPostProcessorCache = null;
}
}
@@ -153,16 +153,6 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
assertThat(accessor.getPropertyValue("object")).isEqualTo(8);
}
@Test
void setterOverload() {
SetterOverload target = new SetterOverload();
BeanWrapper accessor = createAccessor(target);
accessor.setPropertyValue("object", "a String");
assertThat(target.value).isEqualTo("a String");
assertThat(target.getObject()).isEqualTo("a String");
assertThat(accessor.getPropertyValue("object")).isEqualTo("a String");
}
@Test
void propertyDescriptors() throws Exception {
TestBean target = new TestBean();
@@ -216,10 +206,6 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
assertThat(accessor.isReadableProperty("inputStream")).isFalse();
assertThat(accessor.isReadableProperty("filename")).isTrue();
assertThat(accessor.isReadableProperty("description")).isTrue();
accessor = createAccessor(new ActiveResource());
assertThat(accessor.isReadableProperty("resource")).isTrue();
}
@Test
@@ -362,36 +348,6 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
}
public static class SetterOverload {
public String value;
public void setObject(Integer length) {
this.value = length.toString();
}
public void setObject(String object) {
this.value = object;
}
public String getObject() {
return this.value;
}
}
public static class ActiveResource implements AutoCloseable {
public ActiveResource getResource() {
return this;
}
@Override
public void close() throws Exception {
}
}
public static class GetterWithOptional {
public TestBean value;
@@ -722,7 +722,7 @@ class CustomEditorTests {
@Test
void testCustomDateEditor() {
CustomDateEditor editor = new CustomDateEditor(new SimpleDateFormat("MM/dd/yyyy"), false);
CustomDateEditor editor = new CustomDateEditor(null, false);
editor.setValue(null);
assertThat(editor.getValue()).isNull();
assertThat(editor.getAsText()).isEmpty();
@@ -730,7 +730,7 @@ class CustomEditorTests {
@Test
void testCustomDateEditorWithEmptyAsNull() {
CustomDateEditor editor = new CustomDateEditor(new SimpleDateFormat("MM/dd/yyyy"), true);
CustomDateEditor editor = new CustomDateEditor(null, true);
editor.setValue(null);
assertThat(editor.getValue()).isNull();
assertThat(editor.getAsText()).isEmpty();
@@ -93,7 +93,7 @@ public class SimpleMailMessage implements MailMessage, Serializable {
@Override
public void setFrom(@Nullable String from) {
public void setFrom(String from) {
this.from = from;
}
@@ -103,7 +103,7 @@ public class SimpleMailMessage implements MailMessage, Serializable {
}
@Override
public void setReplyTo(@Nullable String replyTo) {
public void setReplyTo(String replyTo) {
this.replyTo = replyTo;
}
@@ -113,7 +113,7 @@ public class SimpleMailMessage implements MailMessage, Serializable {
}
@Override
public void setTo(@Nullable String to) {
public void setTo(String to) {
this.to = new String[] {to};
}
@@ -128,12 +128,12 @@ public class SimpleMailMessage implements MailMessage, Serializable {
}
@Override
public void setCc(@Nullable String cc) {
public void setCc(String cc) {
this.cc = new String[] {cc};
}
@Override
public void setCc(@Nullable String... cc) {
public void setCc(String... cc) {
this.cc = cc;
}
@@ -143,12 +143,12 @@ public class SimpleMailMessage implements MailMessage, Serializable {
}
@Override
public void setBcc(@Nullable String bcc) {
public void setBcc(String bcc) {
this.bcc = new String[] {bcc};
}
@Override
public void setBcc(@Nullable String... bcc) {
public void setBcc(String... bcc) {
this.bcc = bcc;
}
@@ -158,7 +158,7 @@ public class SimpleMailMessage implements MailMessage, Serializable {
}
@Override
public void setSentDate(@Nullable Date sentDate) {
public void setSentDate(Date sentDate) {
this.sentDate = sentDate;
}
@@ -168,7 +168,7 @@ public class SimpleMailMessage implements MailMessage, Serializable {
}
@Override
public void setSubject(@Nullable String subject) {
public void setSubject(String subject) {
this.subject = subject;
}
@@ -178,7 +178,7 @@ public class SimpleMailMessage implements MailMessage, Serializable {
}
@Override
public void setText(@Nullable String text) {
public void setText(String text) {
this.text = text;
}
@@ -77,23 +77,6 @@ public class LoggingCacheErrorHandler implements CacheErrorHandler {
this.logStackTraces = logStackTraces;
}
/**
* Create a {@code LoggingCacheErrorHandler} that uses the supplied
* {@code loggerName} and {@code logStackTraces} flag.
* @param loggerName the name of the logger to use. The name will be passed
* to the underlying logger implementation through Commons Logging, getting
* interpreted as log category according to the logger's configuration.
* @param logStackTraces whether to log stack traces
* @since 5.3.24
* @see org.apache.commons.logging.LogFactory#getLog(String)
* @see java.util.logging.Logger#getLogger(String)
*/
public LoggingCacheErrorHandler(String loggerName, boolean logStackTraces) {
Assert.notNull(loggerName, "'loggerName' must not be null");
this.logger = LogFactory.getLog(loggerName);
this.logStackTraces = logStackTraces;
}
@Override
public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -96,8 +96,6 @@ public class Jsr310DateTimeFormatAnnotationFormatterFactory extends EmbeddedValu
@Override
@SuppressWarnings("unchecked")
public Parser<?> getParser(DateTimeFormat annotation, Class<?> fieldType) {
DateTimeFormatter formatter = getFormatter(annotation, fieldType);
List<String> resolvedFallbackPatterns = new ArrayList<>();
for (String fallbackPattern : annotation.fallbackPatterns()) {
String resolvedFallbackPattern = resolveEmbeddedValue(fallbackPattern);
@@ -106,6 +104,7 @@ public class Jsr310DateTimeFormatAnnotationFormatterFactory extends EmbeddedValu
}
}
DateTimeFormatter formatter = getFormatter(annotation, fieldType);
return new TemporalAccessorParser((Class<? extends TemporalAccessor>) fieldType,
formatter, resolvedFallbackPatterns.toArray(new String[0]), annotation);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -71,8 +71,7 @@ public final class TemporalAccessorParser implements Parser<TemporalAccessor> {
}
TemporalAccessorParser(Class<? extends TemporalAccessor> temporalAccessorType, DateTimeFormatter formatter,
@Nullable String[] fallbackPatterns, @Nullable Object source) {
@Nullable String[] fallbackPatterns, @Nullable Object source) {
this.temporalAccessorType = temporalAccessorType;
this.formatter = formatter;
this.fallbackPatterns = fallbackPatterns;
@@ -101,8 +100,8 @@ public final class TemporalAccessorParser implements Parser<TemporalAccessor> {
}
if (this.source != null) {
throw new DateTimeParseException(
String.format("Unable to parse date time value \"%s\" using configuration from %s", text, this.source),
text, ex.getErrorIndex(), ex);
String.format("Unable to parse date time value \"%s\" using configuration from %s", text, this.source),
text, ex.getErrorIndex(), ex);
}
// else rethrow original exception
throw ex;
@@ -23,7 +23,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.cache.Cache;
import org.springframework.cache.support.NoOpCache;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -85,10 +84,4 @@ class LoggingCacheErrorHandlerTests {
verify(this.logger).warn("Cache 'NOOP' failed to get entry with key 'enigma'", exception);
}
@Test
void constructorWithLoggerName() {
assertThatCode(() -> new LoggingCacheErrorHandler("org.apache.commons.logging.Log", true))
.doesNotThrowAnyException();
}
}
@@ -30,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Stephane Nicoll
*/
class Gh29105Tests {
public class Gh29105Tests {
@Test
void beanProviderWithParentContextReuseOrder() {
@@ -47,7 +47,6 @@ class Gh29105Tests {
List<Class<?>> orderedTypes = child.getBeanProvider(MyService.class)
.orderedStream().map(Object::getClass).collect(Collectors.toList());
assertThat(orderedTypes).containsExactly(CustomService.class, DefaultService.class);
child.close();
}
@@ -79,5 +78,4 @@ class Gh29105Tests {
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -433,16 +433,6 @@ public abstract class AnnotatedElementUtils {
* single annotation and within annotation hierarchies.
* <p>This method follows <em>get semantics</em> as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* <p><strong>WARNING</strong>: if the supplied {@code containerType} is not
* {@code null}, the search will be restricted to supporting only repeatable
* annotations whose container is the supplied {@code containerType}. This
* prevents the search from finding repeatable annotations declared as
* meta-annotations on other types of repeatable annotations. If you need to
* support such a use case, favor {@link #getMergedRepeatableAnnotations(AnnotatedElement, Class)}
* over this method or alternatively use the {@link MergedAnnotations} API
* directly in conjunction with {@link RepeatableContainers} that are
* {@linkplain RepeatableContainers#and(Class, Class) composed} to support
* multiple repeatable annotation types.
* @param element the annotated element (never {@code null})
* @param annotationType the annotation type to find (never {@code null})
* @param containerType the type of the container that holds the annotations;
@@ -735,16 +725,6 @@ public abstract class AnnotatedElementUtils {
* single annotation and within annotation hierarchies.
* <p>This method follows <em>find semantics</em> as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* <p><strong>WARNING</strong>: if the supplied {@code containerType} is not
* {@code null}, the search will be restricted to supporting only repeatable
* annotations whose container is the supplied {@code containerType}. This
* prevents the search from finding repeatable annotations declared as
* meta-annotations on other types of repeatable annotations. If you need to
* support such a use case, favor {@link #findMergedRepeatableAnnotations(AnnotatedElement, Class)}
* over this method or alternatively use the {@link MergedAnnotations} API
* directly in conjunction with {@link RepeatableContainers} that are
* {@linkplain RepeatableContainers#and(Class, Class) composed} to support
* multiple repeatable annotation types.
* @param element the annotated element (never {@code null})
* @param annotationType the annotation type to find (never {@code null})
* @param containerType the type of the container that holds the annotations;
@@ -776,23 +756,7 @@ public abstract class AnnotatedElementUtils {
private static MergedAnnotations getRepeatableAnnotations(AnnotatedElement element,
@Nullable Class<? extends Annotation> containerType, Class<? extends Annotation> annotationType) {
RepeatableContainers repeatableContainers;
if (containerType == null) {
// Invoke RepeatableContainers.of() in order to adhere to the contract of
// getMergedRepeatableAnnotations() which states that an IllegalArgumentException
// will be thrown if the container cannot be resolved.
//
// In any case, we use standardRepeatables() in order to support repeatable
// annotations on other types of repeatable annotations (i.e., nested repeatable
// annotation types).
//
// See https://github.com/spring-projects/spring-framework/issues/20279
RepeatableContainers.of(annotationType, null);
repeatableContainers = RepeatableContainers.standardRepeatables();
}
else {
repeatableContainers = RepeatableContainers.of(annotationType, containerType);
}
RepeatableContainers repeatableContainers = RepeatableContainers.of(annotationType, containerType);
return MergedAnnotations.from(element, SearchStrategy.INHERITED_ANNOTATIONS, repeatableContainers);
}
@@ -803,23 +767,7 @@ public abstract class AnnotatedElementUtils {
private static MergedAnnotations findRepeatableAnnotations(AnnotatedElement element,
@Nullable Class<? extends Annotation> containerType, Class<? extends Annotation> annotationType) {
RepeatableContainers repeatableContainers;
if (containerType == null) {
// Invoke RepeatableContainers.of() in order to adhere to the contract of
// findMergedRepeatableAnnotations() which states that an IllegalArgumentException
// will be thrown if the container cannot be resolved.
//
// In any case, we use standardRepeatables() in order to support repeatable
// annotations on other types of repeatable annotations (i.e., nested repeatable
// annotation types).
//
// See https://github.com/spring-projects/spring-framework/issues/20279
RepeatableContainers.of(annotationType, null);
repeatableContainers = RepeatableContainers.standardRepeatables();
}
else {
repeatableContainers = RepeatableContainers.of(annotationType, containerType);
}
RepeatableContainers repeatableContainers = RepeatableContainers.of(annotationType, containerType);
return MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY, repeatableContainers);
}
@@ -829,7 +777,8 @@ public abstract class AnnotatedElementUtils {
}
private static <A extends Annotation> Comparator<MergedAnnotation<A>> highAggregateIndexesFirst() {
return Comparator.<MergedAnnotation<A>> comparingInt(MergedAnnotation::getAggregateIndex).reversed();
return Comparator.<MergedAnnotation<A>> comparingInt(
MergedAnnotation::getAggregateIndex).reversed();
}
@Nullable
@@ -839,12 +788,13 @@ public abstract class AnnotatedElementUtils {
if (!annotation.isPresent()) {
return null;
}
return annotation.asAnnotationAttributes(Adapt.values(classValuesAsString, nestedAnnotationsAsMap));
return annotation.asAnnotationAttributes(
Adapt.values(classValuesAsString, nestedAnnotationsAsMap));
}
/**
* Adapted {@link AnnotatedElement} that holds specific annotations.
* Adapted {@link AnnotatedElement} that hold specific annotations.
*/
private static class AnnotatedElementForAnnotations implements AnnotatedElement {
@@ -32,6 +32,7 @@ import java.util.Set;
import org.springframework.core.annotation.AnnotationTypeMapping.MirrorSets.MirrorSet;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
@@ -240,7 +241,7 @@ final class AnnotationTypeMapping {
mapping.claimedAliases.addAll(aliases);
if (mapping.annotation != null) {
int[] resolvedMirrors = mapping.mirrorSets.resolve(null,
mapping.annotation, AnnotationUtils::invokeAnnotationMethod);
mapping.annotation, ReflectionUtils::invokeMethod);
for (int i = 0; i < mapping.attributes.size(); i++) {
if (aliases.contains(mapping.attributes.get(i))) {
this.annotationValueMappings[attributeIndex] = resolvedMirrors[i];
@@ -504,7 +505,7 @@ final class AnnotationTypeMapping {
if (source == this && metaAnnotationsOnly) {
return null;
}
return AnnotationUtils.invokeAnnotationMethod(source.attributes.get(mappedIndex), source.annotation);
return ReflectionUtils.invokeMethod(source.attributes.get(mappedIndex), source.annotation);
}
/**
@@ -593,7 +594,7 @@ final class AnnotationTypeMapping {
AttributeMethods attributes = AttributeMethods.forAnnotationType(annotation.annotationType());
for (int i = 0; i < attributes.size(); i++) {
Method attribute = attributes.get(i);
Object value1 = AnnotationUtils.invokeAnnotationMethod(attribute, annotation);
Object value1 = ReflectionUtils.invokeMethod(attribute, annotation);
Object value2;
if (extractedValue instanceof TypeMappedAnnotation) {
value2 = ((TypeMappedAnnotation<?>) extractedValue).getValue(attribute.getName()).orElse(null);
@@ -19,10 +19,9 @@ package org.springframework.core.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -1053,42 +1052,23 @@ public abstract class AnnotationUtils {
}
try {
Method method = annotation.annotationType().getDeclaredMethod(attributeName);
return invokeAnnotationMethod(method, annotation);
ReflectionUtils.makeAccessible(method);
return method.invoke(annotation);
}
catch (NoSuchMethodException ex) {
return null;
}
catch (InvocationTargetException ex) {
rethrowAnnotationConfigurationException(ex.getTargetException());
throw new IllegalStateException("Could not obtain value for annotation attribute '" +
attributeName + "' in " + annotation, ex);
}
catch (Throwable ex) {
rethrowAnnotationConfigurationException(ex);
handleIntrospectionFailure(annotation.getClass(), ex);
return null;
}
}
/**
* Invoke the supplied annotation attribute {@link Method} on the supplied
* {@link Annotation}.
* <p>An attempt will first be made to invoke the method via the annotation's
* {@link InvocationHandler} (if the annotation instance is a JDK dynamic proxy).
* If that fails, an attempt will be made to invoke the method via reflection.
* @param method the method to invoke
* @param annotation the annotation on which to invoke the method
* @return the value returned from the method invocation
* @since 5.3.24
*/
static Object invokeAnnotationMethod(Method method, Object annotation) {
if (Proxy.isProxyClass(annotation.getClass())) {
try {
InvocationHandler handler = Proxy.getInvocationHandler(annotation);
return handler.invoke(annotation, method, null);
}
catch (Throwable ex) {
// ignore and fall back to reflection below
}
}
return ReflectionUtils.invokeMethod(method, annotation);
}
/**
* If the supplied throwable is an {@link AnnotationConfigurationException},
* it will be cast to an {@code AnnotationConfigurationException} and thrown,
@@ -109,7 +109,7 @@ final class AttributeMethods {
for (int i = 0; i < size(); i++) {
if (canThrowTypeNotPresentException(i)) {
try {
AnnotationUtils.invokeAnnotationMethod(get(i), annotation);
get(i).invoke(annotation);
}
catch (Throwable ex) {
return false;
@@ -134,7 +134,7 @@ final class AttributeMethods {
for (int i = 0; i < size(); i++) {
if (canThrowTypeNotPresentException(i)) {
try {
AnnotationUtils.invokeAnnotationMethod(get(i), annotation);
get(i).invoke(annotation);
}
catch (Throwable ex) {
throw new IllegalStateException("Could not obtain annotation attribute value for " +
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -25,6 +25,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
/**
* Strategy used to determine annotations that act as containers for other
@@ -38,7 +39,6 @@ import org.springframework.util.ObjectUtils;
* <p>To completely disable repeatable support use {@link #none()}.
*
* @author Phillip Webb
* @author Sam Brannen
* @since 5.2
*/
public abstract class RepeatableContainers {
@@ -101,19 +101,15 @@ public abstract class RepeatableContainers {
}
/**
* Create a {@link RepeatableContainers} instance that uses predefined
* repeatable and container types.
* @param repeatable the contained repeatable annotation type
* @param container the container annotation type or {@code null}. If specified,
* Create a {@link RepeatableContainers} instance that uses a defined
* container and repeatable type.
* @param repeatable the contained repeatable annotation
* @param container the container annotation or {@code null}. If specified,
* this annotation must declare a {@code value} attribute returning an array
* of repeatable annotations. If not specified, the container will be
* deduced by inspecting the {@code @Repeatable} annotation on
* {@code repeatable}.
* @return a {@link RepeatableContainers} instance
* @throws IllegalArgumentException if the supplied container type is
* {@code null} and the annotation type is not a repeatable annotation
* @throws AnnotationConfigurationException if the supplied container type
* is not a properly configured container for a repeatable annotation
*/
public static RepeatableContainers of(
Class<? extends Annotation> repeatable, @Nullable Class<? extends Annotation> container) {
@@ -152,7 +148,7 @@ public abstract class RepeatableContainers {
Annotation[] findRepeatedAnnotations(Annotation annotation) {
Method method = getRepeatedAnnotationsMethod(annotation.annotationType());
if (method != null) {
return (Annotation[]) AnnotationUtils.invokeAnnotationMethod(method, annotation);
return (Annotation[]) ReflectionUtils.invokeMethod(method, annotation);
}
return super.findRepeatedAnnotations(annotation);
}
@@ -239,7 +235,7 @@ public abstract class RepeatableContainers {
@Nullable
Annotation[] findRepeatedAnnotations(Annotation annotation) {
if (this.container.isAssignableFrom(annotation.annotationType())) {
return (Annotation[]) AnnotationUtils.invokeAnnotationMethod(this.valueMethod, annotation);
return (Annotation[]) ReflectionUtils.invokeMethod(this.valueMethod, annotation);
}
return super.findRepeatedAnnotations(annotation);
}
@@ -111,7 +111,7 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i
for (int i = 0; i < this.attributes.size(); i++) {
Method attribute = this.attributes.get(i);
Object thisValue = getAttributeValue(attribute);
Object otherValue = AnnotationUtils.invokeAnnotationMethod(attribute, other);
Object otherValue = ReflectionUtils.invokeMethod(attribute, other);
if (!ObjectUtils.nullSafeEquals(thisValue, otherValue)) {
return false;
}
@@ -33,6 +33,7 @@ import java.util.function.Predicate;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* {@link MergedAnnotation} that adapts attributes from a root annotation by
@@ -42,9 +43,9 @@ import org.springframework.util.ClassUtils;
* {@code BiFunction}. This allows various different annotation models to be
* supported by the same class. For example, the attributes source might be an
* actual {@link Annotation} instance where methods on the annotation instance
* are {@linkplain AnnotationUtils#invokeAnnotationMethod(Method, Object) invoked}
* to extract values. Similarly, the source could be a simple {@link Map} with
* values extracted using {@link Map#get(Object)}.
* are {@linkplain ReflectionUtils#invokeMethod(Method, Object) invoked} to extract
* values. Equally, the source could be a simple {@link Map} with values
* extracted using {@link Map#get(Object)}.
*
* <p>Extracted root attribute values must be compatible with the attribute
* return type, namely:
@@ -433,7 +434,7 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
}
if (value == null) {
Method attribute = this.mapping.getAttributes().get(attributeIndex);
value = AnnotationUtils.invokeAnnotationMethod(attribute, this.mapping.getAnnotation());
value = ReflectionUtils.invokeMethod(attribute, this.mapping.getAnnotation());
}
return value;
}
@@ -554,7 +555,7 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
private ValueExtractor getValueExtractor(Object value) {
if (value instanceof Annotation) {
return AnnotationUtils::invokeAnnotationMethod;
return ReflectionUtils::invokeMethod;
}
if (value instanceof Map) {
return TypeMappedAnnotation::extractFromMap;
@@ -614,8 +615,7 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
static <A extends Annotation> MergedAnnotation<A> from(@Nullable Object source, A annotation) {
Assert.notNull(annotation, "Annotation must not be null");
AnnotationTypeMappings mappings = AnnotationTypeMappings.forAnnotationType(annotation.annotationType());
return new TypeMappedAnnotation<>(
mappings.get(0), null, source, annotation, AnnotationUtils::invokeAnnotationMethod, 0);
return new TypeMappedAnnotation<>(mappings.get(0), null, source, annotation, ReflectionUtils::invokeMethod, 0);
}
static <A extends Annotation> MergedAnnotation<A> of(
@@ -649,7 +649,7 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
int aggregateIndex, IntrospectionFailureLogger logger) {
return createIfPossible(mapping, source, annotation,
AnnotationUtils::invokeAnnotationMethod, aggregateIndex, logger);
ReflectionUtils::invokeMethod, aggregateIndex, logger);
}
@Nullable
@@ -177,7 +177,7 @@ public abstract class DataBufferUtils {
if (options.length > 0) {
for (OpenOption option : options) {
Assert.isTrue(!(option == StandardOpenOption.APPEND || option == StandardOpenOption.WRITE),
() -> "'" + option + "' not allowed");
"'" + option + "' not allowed");
}
}
@@ -695,7 +695,7 @@ public abstract class DataBufferUtils {
@Override
public byte[] delimiter() {
Assert.state(this.longestDelimiter != NO_DELIMITER, "'delimiter' not set");
Assert.state(this.longestDelimiter != NO_DELIMITER, "Illegal state!");
return this.longestDelimiter;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -85,7 +85,7 @@ public abstract class CollectionUtils {
* @see #newLinkedHashMap(int)
*/
public static <K, V> HashMap<K, V> newHashMap(int expectedSize) {
return new HashMap<>(computeMapInitialCapacity(expectedSize), DEFAULT_LOAD_FACTOR);
return new HashMap<>((int) (expectedSize / DEFAULT_LOAD_FACTOR), DEFAULT_LOAD_FACTOR);
}
/**
@@ -102,11 +102,7 @@ public abstract class CollectionUtils {
* @see #newHashMap(int)
*/
public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(int expectedSize) {
return new LinkedHashMap<>(computeMapInitialCapacity(expectedSize), DEFAULT_LOAD_FACTOR);
}
private static int computeMapInitialCapacity(int expectedSize) {
return (int) Math.ceil(expectedSize / (double) DEFAULT_LOAD_FACTOR);
return new LinkedHashMap<>((int) (expectedSize / DEFAULT_LOAD_FACTOR), DEFAULT_LOAD_FACTOR);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -34,6 +34,7 @@ import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.util.LinkedMultiValueMap;
@@ -155,7 +156,7 @@ class CollectionFactoryTests {
@Test
void createApproximateCollectionFromEmptyHashSet() {
Collection<String> set = createApproximateCollection(new HashSet<String>(), 2);
assertThat(set).isEmpty();
Assertions.assertThat(set).isEmpty();
}
@Test
@@ -1,212 +0,0 @@
/*
* Copyright 2002-2022 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.core.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.Set;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.util.ReflectionUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for various ways to search for repeatable annotations that are
* nested (i.e., repeatable annotations used as meta-annotations on other
* repeatable annotations).
*
* @author Sam Brannen
* @since 5.3.24
* @see https://github.com/spring-projects/spring-framework/issues/20279
*/
@SuppressWarnings("unused")
class NestedRepeatableAnnotationsTests {
@Nested
class SingleRepeatableAnnotationTests {
private final Method method = ReflectionUtils.findMethod(getClass(), "annotatedMethod");
@Test
void streamRepeatableAnnotations_MergedAnnotationsApi() {
Set<A> annotations = MergedAnnotations.from(method, SearchStrategy.TYPE_HIERARCHY)
.stream(A.class).collect(MergedAnnotationCollectors.toAnnotationSet());
// Merged, so we expect to find @A once with its value coming from @B(5).
assertThat(annotations).extracting(A::value).containsExactly(5);
}
@Test
void findMergedRepeatableAnnotations_AnnotatedElementUtils() {
Set<A> annotations = AnnotatedElementUtils.findMergedRepeatableAnnotations(method, A.class);
// Merged, so we expect to find @A once with its value coming from @B(5).
assertThat(annotations).extracting(A::value).containsExactly(5);
}
@Test
void getMergedRepeatableAnnotationsWithStandardRepeatables_AnnotatedElementUtils() {
Set<A> annotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, A.class);
// Merged, so we expect to find @A once with its value coming from @B(5).
assertThat(annotations).extracting(A::value).containsExactly(5);
}
@Test
void getMergedRepeatableAnnotationsWithExplicitContainer_AnnotatedElementUtils() {
Set<A> annotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, A.class, A.Container.class);
// Merged, so we expect to find @A once with its value coming from @B(5).
assertThat(annotations).extracting(A::value).containsExactly(5);
}
@Test
@SuppressWarnings("deprecation")
void getRepeatableAnnotations_AnnotationUtils() {
Set<A> annotations = AnnotationUtils.getRepeatableAnnotations(method, A.class);
// Not merged, so we expect to find @A once with the default value of 0.
// @A will actually be found twice, but we have Set semantics here.
assertThat(annotations).extracting(A::value).containsExactly(0);
}
@B(5)
void annotatedMethod() {
}
}
@Nested
class MultipleRepeatableAnnotationsTests {
private final Method method = ReflectionUtils.findMethod(getClass(), "annotatedMethod");
@Test
void streamRepeatableAnnotationsWithStandardRepeatables_MergedAnnotationsApi() {
RepeatableContainers repeatableContainers = RepeatableContainers.standardRepeatables();
Set<A> annotations = MergedAnnotations.from(method, SearchStrategy.TYPE_HIERARCHY, repeatableContainers)
.stream(A.class).collect(MergedAnnotationCollectors.toAnnotationSet());
// Merged, so we expect to find @A twice with values coming from @B(5) and @B(10).
assertThat(annotations).extracting(A::value).containsExactly(5, 10);
}
@Test
void streamRepeatableAnnotationsWithExplicitRepeatables_MergedAnnotationsApi() {
RepeatableContainers repeatableContainers =
RepeatableContainers.of(A.class, A.Container.class).and(B.Container.class, B.class);
Set<A> annotations = MergedAnnotations.from(method, SearchStrategy.TYPE_HIERARCHY, repeatableContainers)
.stream(A.class).collect(MergedAnnotationCollectors.toAnnotationSet());
// Merged, so we expect to find @A twice with values coming from @B(5) and @B(10).
assertThat(annotations).extracting(A::value).containsExactly(5, 10);
}
@Test
void findMergedRepeatableAnnotationsWithStandardRepeatables_AnnotatedElementUtils() {
Set<A> annotations = AnnotatedElementUtils.findMergedRepeatableAnnotations(method, A.class);
// Merged, so we expect to find @A twice with values coming from @B(5) and @B(10).
assertThat(annotations).extracting(A::value).containsExactly(5, 10);
}
@Test
void findMergedRepeatableAnnotationsWithExplicitContainer_AnnotatedElementUtils() {
Set<A> annotations = AnnotatedElementUtils.findMergedRepeatableAnnotations(method, A.class, A.Container.class);
// When findMergedRepeatableAnnotations(...) is invoked with an explicit container
// type, it uses RepeatableContainers.of(...) which limits the repeatable annotation
// support to a single container type.
//
// In this test case, we are therefore limiting the support to @A.Container, which
// means that @B.Container is unsupported and effectively ignored as a repeatable
// container type.
//
// Long story, short: the search doesn't find anything.
assertThat(annotations).isEmpty();
}
@Test
void getMergedRepeatableAnnotationsWithStandardRepeatables_AnnotatedElementUtils() {
Set<A> annotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, A.class);
// Merged, so we expect to find @A twice with values coming from @B(5) and @B(10).
assertThat(annotations).extracting(A::value).containsExactly(5, 10);
}
@Test
void getMergedRepeatableAnnotationsWithExplicitContainer_AnnotatedElementUtils() {
Set<A> annotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, A.class, A.Container.class);
// When getMergedRepeatableAnnotations(...) is invoked with an explicit container
// type, it uses RepeatableContainers.of(...) which limits the repeatable annotation
// support to a single container type.
//
// In this test case, we are therefore limiting the support to @A.Container, which
// means that @B.Container is unsupported and effectively ignored as a repeatable
// container type.
//
// Long story, short: the search doesn't find anything.
assertThat(annotations).isEmpty();
}
@Test
@SuppressWarnings("deprecation")
void getRepeatableAnnotations_AnnotationUtils() {
Set<A> annotations = AnnotationUtils.getRepeatableAnnotations(method, A.class);
// Not merged, so we expect to find a single @A with default value of 0.
// @A will actually be found twice, but we have Set semantics here.
assertThat(annotations).extracting(A::value).containsExactly(0);
}
@B(5)
@B(10)
void annotatedMethod() {
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Repeatable(A.Container.class)
@interface A {
int value() default 0;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@interface Container {
A[] value();
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Repeatable(B.Container.class)
@A
@A
@interface B {
@AliasFor(annotation = A.class)
int value();
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@interface Container {
B[] value();
}
}
}
@@ -63,7 +63,7 @@ class ResourceRegionEncoderTests extends AbstractLeakCheckingTests {
}
@Test
void shouldEncodeResourceRegionFileResource() {
void shouldEncodeResourceRegionFileResource() throws Exception {
ResourceRegion region = new ResourceRegion(
new ClassPathResource("ResourceRegionEncoderTests.txt", getClass()), 0, 6);
Flux<DataBuffer> result = this.encoder.encode(Mono.just(region), this.bufferFactory,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -35,7 +35,8 @@ class LeakAwareDataBufferFactoryTests {
void leak() {
DataBuffer dataBuffer = this.bufferFactory.allocateBuffer();
try {
assertThatExceptionOfType(AssertionError.class).isThrownBy(this.bufferFactory::checkForLeaks);
assertThatExceptionOfType(AssertionError.class).isThrownBy(
this.bufferFactory::checkForLeaks);
}
finally {
release(dataBuffer);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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,19 +16,16 @@
package org.springframework.core.io.support;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
@@ -36,9 +33,8 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link PathMatchingResourcePatternResolver}.
*
* <p>If tests fail, uncomment the diagnostics in {@link #assertFilenames(String, boolean, String...)}.
* If this test case fails, uncomment diagnostics in the
* {@link #assertProtocolAndFilenames} method.
*
* @author Oliver Hutchison
* @author Juergen Hoeller
@@ -48,261 +44,124 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
*/
class PathMatchingResourcePatternResolverTests {
private static final String[] CLASSES_IN_CORE_IO_SUPPORT = { "EncodedResource.class",
"LocalizedResourceHelper.class", "PathMatchingResourcePatternResolver.class", "PropertiesLoaderSupport.class",
"PropertiesLoaderUtils.class", "ResourceArrayPropertyEditor.class", "ResourcePatternResolver.class",
"ResourcePatternUtils.class", "SpringFactoriesLoader.class" };
private static final String[] CLASSES_IN_CORE_IO_SUPPORT =
new String[] {"EncodedResource.class", "LocalizedResourceHelper.class",
"PathMatchingResourcePatternResolver.class", "PropertiesLoaderSupport.class",
"PropertiesLoaderUtils.class", "ResourceArrayPropertyEditor.class",
"ResourcePatternResolver.class", "ResourcePatternUtils.class"};
private static final String[] TEST_CLASSES_IN_CORE_IO_SUPPORT = { "PathMatchingResourcePatternResolverTests.class" };
private static final String[] TEST_CLASSES_IN_CORE_IO_SUPPORT =
new String[] {"PathMatchingResourcePatternResolverTests.class"};
private static final String[] CLASSES_IN_REACTOR_UTIL_ANNOTATION = { "NonNull.class", "NonNullApi.class", "Nullable.class" };
private static final String[] CLASSES_IN_REACTOR_UTIL_ANNOTATIONS =
new String[] {"NonNull.class", "NonNullApi.class", "Nullable.class"};
private PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
private final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
@Test
void invalidPrefixWithPatternElementInIt() throws IOException {
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() ->
resolver.getResources("xx**:**/*.xy"));
}
@Test
void singleResourceOnFileSystem() throws IOException {
Resource[] resources =
resolver.getResources("org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.class");
assertThat(resources.length).isEqualTo(1);
assertProtocolAndFilenames(resources, "file", "PathMatchingResourcePatternResolverTests.class");
}
@Nested
class InvalidPatterns {
@Test
void singleResourceInJar() throws IOException {
Resource[] resources = resolver.getResources("org/reactivestreams/Publisher.class");
assertThat(resources.length).isEqualTo(1);
assertProtocolAndFilenames(resources, "jar", "Publisher.class");
}
@Test
void invalidPrefixWithPatternElementInItThrowsException() {
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() -> resolver.getResources("xx**:**/*.xy"));
@Disabled
@Test
void classpathStarWithPatternOnFileSystem() throws IOException {
Resource[] resources = resolver.getResources("classpath*:org/springframework/core/io/sup*/*.class");
// Have to exclude Clover-generated class files here,
// as we might be running as part of a Clover test run.
List<Resource> noCloverResources = new ArrayList<>();
for (Resource resource : resources) {
if (!resource.getFilename().contains("$__CLOVER_")) {
noCloverResources.add(resource);
}
}
resources = noCloverResources.toArray(new Resource[0]);
assertProtocolAndFilenames(resources, "file",
StringUtils.concatenateStringArrays(CLASSES_IN_CORE_IO_SUPPORT, TEST_CLASSES_IN_CORE_IO_SUPPORT));
}
@Test
void getResourcesOnFileSystemContainingHashtagsInTheirFileNames() throws IOException {
Resource[] resources = resolver.getResources("classpath*:org/springframework/core/io/**/resource#test*.txt");
assertThat(resources).extracting(Resource::getFile).extracting(File::getName)
.containsExactlyInAnyOrder("resource#test1.txt", "resource#test2.txt");
}
@Test
void classpathWithPatternInJar() throws IOException {
Resource[] resources = resolver.getResources("classpath:reactor/util/annotation/*.class");
assertProtocolAndFilenames(resources, "jar", CLASSES_IN_REACTOR_UTIL_ANNOTATIONS);
}
@Test
void classpathStarWithPatternInJar() throws IOException {
Resource[] resources = resolver.getResources("classpath*:reactor/util/annotation/*.class");
assertProtocolAndFilenames(resources, "jar", CLASSES_IN_REACTOR_UTIL_ANNOTATIONS);
}
@Test
void rootPatternRetrievalInJarFiles() throws IOException {
Resource[] resources = resolver.getResources("classpath*:*.dtd");
boolean found = false;
for (Resource resource : resources) {
if (resource.getFilename().equals("aspectj_1_5_0.dtd")) {
found = true;
break;
}
}
assertThat(found).as("Could not find aspectj_1_5_0.dtd in the root of the aspectjweaver jar").isTrue();
}
@Nested
class FileSystemResources {
private void assertProtocolAndFilenames(Resource[] resources, String protocol, String... filenames)
throws IOException {
@Test
void singleResourceOnFileSystem() {
String pattern = "org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.class";
assertExactFilenames(pattern, "PathMatchingResourcePatternResolverTests.class");
}
// Uncomment the following if you encounter problems with matching against the file system
// It shows file locations.
// String[] actualNames = new String[resources.length];
// for (int i = 0; i < resources.length; i++) {
// actualNames[i] = resources[i].getFilename();
// }
// List sortedActualNames = new LinkedList(Arrays.asList(actualNames));
// List expectedNames = new LinkedList(Arrays.asList(fileNames));
// Collections.sort(sortedActualNames);
// Collections.sort(expectedNames);
//
// System.out.println("-----------");
// System.out.println("Expected: " + StringUtils.collectionToCommaDelimitedString(expectedNames));
// System.out.println("Actual: " + StringUtils.collectionToCommaDelimitedString(sortedActualNames));
// for (int i = 0; i < resources.length; i++) {
// System.out.println(resources[i]);
// }
@Test
void classpathStarWithPatternOnFileSystem() {
String pattern = "classpath*:org/springframework/core/io/sup*/*.class";
String[] expectedFilenames = StringUtils.concatenateStringArrays(CLASSES_IN_CORE_IO_SUPPORT, TEST_CLASSES_IN_CORE_IO_SUPPORT);
assertFilenames(pattern, expectedFilenames);
}
@Nested
class WithHashtagsInTheirFileNames {
@Test
void usingClasspathStarProtocol() {
String pattern = "classpath*:org/springframework/core/io/**/resource#test*.txt";
String pathPrefix = ".+org/springframework/core/io/";
assertExactFilenames(pattern, "resource#test1.txt", "resource#test2.txt");
assertExactSubPaths(pattern, pathPrefix, "support/resource#test1.txt", "support/resource#test2.txt");
}
@Test
void usingClasspathStarProtocolWithWildcardInPatternAndNotEndingInSlash() throws Exception {
String pattern = "classpath*:org/springframework/core/io/sup*";
String pathPrefix = ".+org/springframework/core/io/";
List<String> actualSubPaths = getSubPathsIgnoringClassFiles(pattern, pathPrefix);
// We DO find "support" if the pattern does NOT end with a slash.
assertThat(actualSubPaths).containsExactly("support");
}
@Test
void usingFileProtocolWithWildcardInPatternAndNotEndingInSlash() throws Exception {
Path testResourcesDir = Paths.get("src/test/resources").toAbsolutePath();
String pattern = String.format("file:%s/org/springframework/core/io/sup*", testResourcesDir);
String pathPrefix = ".+org/springframework/core/io/";
List<String> actualSubPaths = getSubPathsIgnoringClassFiles(pattern, pathPrefix);
// We DO find "support" if the pattern does NOT end with a slash.
assertThat(actualSubPaths).containsExactly("support");
}
@Test
void usingClasspathStarProtocolWithWildcardInPatternAndEndingInSlash() throws Exception {
String pattern = "classpath*:org/springframework/core/io/sup*/";
String pathPrefix = ".+org/springframework/core/io/";
List<String> actualSubPaths = getSubPathsIgnoringClassFiles(pattern, pathPrefix);
// We do NOT find "support" if the pattern ENDS with a slash.
assertThat(actualSubPaths).isEmpty();
}
@Test
void usingFileProtocolWithWildcardInPatternAndEndingInSlash() throws Exception {
Path testResourcesDir = Paths.get("src/test/resources").toAbsolutePath();
String pattern = String.format("file:%s/org/springframework/core/io/sup*/", testResourcesDir);
String pathPrefix = ".+org/springframework/core/io/";
List<String> actualSubPaths = getSubPathsIgnoringClassFiles(pattern, pathPrefix);
// We do NOT find "support" if the pattern ENDS with a slash.
assertThat(actualSubPaths).isEmpty();
}
@Test
void usingClasspathStarProtocolWithWildcardInPatternAndEndingWithSuffixPattern() throws Exception {
String pattern = "classpath*:org/springframework/core/io/sup*/*.txt";
String pathPrefix = ".+org/springframework/core/io/";
List<String> actualSubPaths = getSubPathsIgnoringClassFiles(pattern, pathPrefix);
assertThat(actualSubPaths)
.containsExactlyInAnyOrder("support/resource#test1.txt", "support/resource#test2.txt");
}
private List<String> getSubPathsIgnoringClassFiles(String pattern, String pathPrefix) throws IOException {
return Arrays.stream(resolver.getResources(pattern))
.map(resource -> getPath(resource).replaceFirst(pathPrefix, ""))
.filter(name -> !name.endsWith(".class"))
.distinct()
.sorted()
.collect(Collectors.toList());
}
@Test
void usingFileProtocolWithoutWildcardInPatternAndEndingInSlashStarStar() {
Path testResourcesDir = Paths.get("src/test/resources").toAbsolutePath();
String pattern = String.format("file:%s/scanned-resources/**", testResourcesDir);
String pathPrefix = ".+?resources/";
// We do NOT find "scanned-resources" if the pattern ENDS with "/**" AND does NOT otherwise contain a wildcard.
assertExactFilenames(pattern, "resource#test1.txt", "resource#test2.txt");
assertExactSubPaths(pattern, pathPrefix, "scanned-resources/resource#test1.txt",
"scanned-resources/resource#test2.txt");
}
@Test
void usingFileProtocolWithWildcardInPatternAndEndingInSlashStarStar() {
Path testResourcesDir = Paths.get("src/test/resources").toAbsolutePath();
String pattern = String.format("file:%s/scanned*resources/**", testResourcesDir);
String pathPrefix = ".+?resources/";
// We DO find "scanned-resources" if the pattern ENDS with "/**" AND DOES otherwise contain a wildcard.
assertExactFilenames(pattern, "scanned-resources", "resource#test1.txt", "resource#test2.txt");
assertExactSubPaths(pattern, pathPrefix, "scanned-resources", "scanned-resources/resource#test1.txt",
"scanned-resources/resource#test2.txt");
}
@Test
void usingFileProtocolAndAssertingUrlAndUriSyntax() throws Exception {
Path testResourcesDir = Paths.get("src/test/resources").toAbsolutePath();
String pattern = String.format("file:%s/scanned-resources/**/resource#test1.txt", testResourcesDir);
Resource[] resources = resolver.getResources(pattern);
assertThat(resources).hasSize(1);
Resource resource = resources[0];
assertThat(resource.getFilename()).isEqualTo("resource#test1.txt");
// The following assertions serve as regression tests for the lack of the
// "authority component" (//) in the returned URI/URL. For example, we are
// expecting file:/my/path (or file:/C:/My/Path) instead of file:///my/path.
assertThat(resource.getURL().toString()).matches("^file:\\/[^\\/].+test1\\.txt$");
assertThat(resource.getURI().toString()).matches("^file:\\/[^\\/].+test1\\.txt$");
}
assertThat(resources.length).as("Correct number of files found").isEqualTo(filenames.length);
for (Resource resource : resources) {
String actualProtocol = resource.getURL().getProtocol();
assertThat(actualProtocol).isEqualTo(protocol);
assertFilenameIn(resource, filenames);
}
}
@Nested
class JarResources {
@Test
void singleResourceInJar() {
String pattern = "org/reactivestreams/Publisher.class";
assertExactFilenames(pattern, "Publisher.class");
}
@Test
void singleResourceInRootOfJar() {
String pattern = "aspectj_1_5_0.dtd";
assertExactFilenames(pattern, "aspectj_1_5_0.dtd");
}
@Test
void classpathWithPatternInJar() {
String pattern = "classpath:reactor/util/annotation/*.class";
assertExactFilenames(pattern, CLASSES_IN_REACTOR_UTIL_ANNOTATION);
}
@Test
void classpathStarWithPatternInJar() {
String pattern = "classpath*:reactor/util/annotation/*.class";
assertExactFilenames(pattern, CLASSES_IN_REACTOR_UTIL_ANNOTATION);
}
// Fails in a native image -- https://github.com/oracle/graal/issues/5020
@Test
void rootPatternRetrievalInJarFiles() throws IOException {
assertThat(resolver.getResources("classpath*:aspectj*.dtd")).extracting(Resource::getFilename)
.as("Could not find aspectj_1_5_0.dtd in the root of the aspectjweaver jar")
.containsExactly("aspectj_1_5_0.dtd");
}
}
private void assertFilenames(String pattern, String... filenames) {
assertFilenames(pattern, false, filenames);
}
private void assertExactFilenames(String pattern, String... filenames) {
assertFilenames(pattern, true, filenames);
}
private void assertFilenames(String pattern, boolean exactly, String... filenames) {
try {
Resource[] resources = resolver.getResources(pattern);
List<String> actualNames = Arrays.stream(resources)
.map(Resource::getFilename)
.sorted()
.collect(Collectors.toList());
// Uncomment the following if you encounter problems with matching against the file system.
// List<String> expectedNames = Arrays.stream(filenames).sorted().toList();
// System.out.println("----------------------------------------------------------------------");
// System.out.println("Expected: " + expectedNames);
// System.out.println("Actual: " + actualNames);
// Arrays.stream(resources).forEach(System.out::println);
if (exactly) {
assertThat(actualNames).as("subset of files found").containsExactlyInAnyOrder(filenames);
}
else {
assertThat(actualNames).as("subset of files found").contains(filenames);
}
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
private void assertExactSubPaths(String pattern, String pathPrefix, String... subPaths) {
try {
Resource[] resources = resolver.getResources(pattern);
List<String> actualSubPaths = Arrays.stream(resources)
.map(resource -> getPath(resource).replaceFirst(pathPrefix, ""))
.sorted()
.collect(Collectors.toList());
assertThat(actualSubPaths).containsExactlyInAnyOrder(subPaths);
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
private String getPath(Resource resource) {
// Tests fail if we use resouce.getURL().getPath(). They would also fail on Mac OS when
// using resouce.getURI().getPath() if the resource paths are not Unicode normalized.
//
// On the JVM, all tests should pass when using resouce.getFile().getPath(); however,
// we use FileSystemResource#getPath since this test class is sometimes run within a
// GraalVM native image which cannot support Path#toFile.
//
// See: https://github.com/spring-projects/spring-framework/issues/29243
return ((FileSystemResource) resource).getPath();
private void assertFilenameIn(Resource resource, String... filenames) {
String filename = resource.getFilename();
assertThat(Arrays.stream(filenames).anyMatch(filename::endsWith)).as(resource + " does not have a filename that matches any of the specified names").isTrue();
}
}
@@ -50,14 +50,14 @@ class SocketUtilsTests {
@Test
void findAvailableTcpPortWithZeroMinPort() {
assertThatIllegalArgumentException().isThrownBy(
() -> org.springframework.util.SocketUtils.findAvailableTcpPort(0));
assertThatIllegalArgumentException().isThrownBy(() ->
org.springframework.util.SocketUtils.findAvailableTcpPort(0));
}
@Test
void findAvailableTcpPortWithNegativeMinPort() {
assertThatIllegalArgumentException().isThrownBy(
() -> org.springframework.util.SocketUtils.findAvailableTcpPort(-500));
assertThatIllegalArgumentException().isThrownBy(() ->
org.springframework.util.SocketUtils.findAvailableTcpPort(-500));
}
@Test
@@ -80,8 +80,8 @@ class SocketUtilsTests {
try (ServerSocket socket = ServerSocketFactory.getDefault().createServerSocket(port, 1, InetAddress.getByName("localhost"))) {
assertThat(socket).isNotNull();
// will only look for the exact port
assertThatIllegalStateException().isThrownBy(
() -> org.springframework.util.SocketUtils.findAvailableTcpPort(port, port))
assertThatIllegalStateException().isThrownBy(() ->
org.springframework.util.SocketUtils.findAvailableTcpPort(port, port))
.withMessageStartingWith("Could not find an available TCP port")
.withMessageEndingWith("after 1 attempts");
}
@@ -123,7 +123,8 @@ class SocketUtilsTests {
@Test
void findAvailableTcpPortsWithRequestedNumberGreaterThanSizeOfRange() {
assertThatIllegalArgumentException().isThrownBy(() -> findAvailableTcpPorts(50, 45000, 45010));
assertThatIllegalArgumentException().isThrownBy(() ->
findAvailableTcpPorts(50, 45000, 45010));
}
@@ -131,14 +132,14 @@ class SocketUtilsTests {
@Test
void findAvailableUdpPortWithZeroMinPort() {
assertThatIllegalArgumentException().isThrownBy(
() -> org.springframework.util.SocketUtils.findAvailableUdpPort(0));
assertThatIllegalArgumentException().isThrownBy(() ->
org.springframework.util.SocketUtils.findAvailableUdpPort(0));
}
@Test
void findAvailableUdpPortWithNegativeMinPort() {
assertThatIllegalArgumentException().isThrownBy(
() -> org.springframework.util.SocketUtils.findAvailableUdpPort(-500));
assertThatIllegalArgumentException().isThrownBy(() ->
org.springframework.util.SocketUtils.findAvailableUdpPort(-500));
}
@Test
@@ -154,8 +155,8 @@ class SocketUtilsTests {
try (DatagramSocket socket = new DatagramSocket(port, InetAddress.getByName("localhost"))) {
assertThat(socket).isNotNull();
// will only look for the exact port
assertThatIllegalStateException().isThrownBy(
() -> org.springframework.util.SocketUtils.findAvailableUdpPort(port, port))
assertThatIllegalStateException().isThrownBy(() ->
org.springframework.util.SocketUtils.findAvailableUdpPort(port, port))
.withMessageStartingWith("Could not find an available UDP port")
.withMessageEndingWith("after 1 attempts");
}
@@ -197,7 +198,8 @@ class SocketUtilsTests {
@Test
void findAvailableUdpPortsWithRequestedNumberGreaterThanSizeOfRange() {
assertThatIllegalArgumentException().isThrownBy(() -> findAvailableUdpPorts(50, 45000, 45010));
assertThatIllegalArgumentException().isThrownBy(() ->
findAvailableUdpPorts(50, 45000, 45010));
}
@@ -224,13 +226,13 @@ class SocketUtilsTests {
SortedSet<Integer> ports = org.springframework.util.SocketUtils.findAvailableUdpPorts(numRequested, minPort, maxPort);
assertAvailablePorts(ports, numRequested, minPort, maxPort);
}
private void assertPortInRange(int port, int minPort, int maxPort) {
assertThat(port).as("port").isBetween(minPort, maxPort);
assertThat(port >= minPort).as("port [" + port + "] >= " + minPort).isTrue();
assertThat(port <= maxPort).as("port [" + port + "] <= " + maxPort).isTrue();
}
private void assertAvailablePorts(SortedSet<Integer> ports, int numRequested, int minPort, int maxPort) {
assertThat(ports).as("number of ports requested").hasSize(numRequested);
assertThat(ports.size()).as("number of ports requested").isEqualTo(numRequested);
for (int port : ports) {
assertPortInRange(port, minPort, maxPort);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
package org.springframework.core
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
class KotlinBridgeMethodResolverTests {
@@ -25,22 +25,22 @@ class KotlinBridgeMethodResolverTests {
fun findBridgedMethod() {
val unbridged = GenericRepository::class.java.getDeclaredMethod("delete", Int::class.java)
val bridged = GenericRepository::class.java.getDeclaredMethod("delete", Any::class.java)
assertThat(unbridged.isBridge).isFalse
assertThat(bridged.isBridge).isTrue
Assertions.assertThat(unbridged.isBridge).isFalse
Assertions.assertThat(bridged.isBridge).isTrue
assertThat(BridgeMethodResolver.findBridgedMethod(unbridged)).`as`("Unbridged method not returned directly").isEqualTo(unbridged)
assertThat(BridgeMethodResolver.findBridgedMethod(bridged)).`as`("Incorrect bridged method returned").isEqualTo(unbridged)
Assertions.assertThat(BridgeMethodResolver.findBridgedMethod(unbridged)).`as`("Unbridged method not returned directly").isEqualTo(unbridged)
Assertions.assertThat(BridgeMethodResolver.findBridgedMethod(bridged)).`as`("Incorrect bridged method returned").isEqualTo(unbridged)
}
@Test
fun findBridgedMethodWithArrays() {
val unbridged = GenericRepository::class.java.getDeclaredMethod("delete", Array<Int>::class.java)
val bridged = GenericRepository::class.java.getDeclaredMethod("delete", Array<Any>::class.java)
assertThat(unbridged.isBridge).isFalse
assertThat(bridged.isBridge).isTrue
Assertions.assertThat(unbridged.isBridge).isFalse
Assertions.assertThat(bridged.isBridge).isTrue
assertThat(BridgeMethodResolver.findBridgedMethod(unbridged)).`as`("Unbridged method not returned directly").isEqualTo(unbridged)
assertThat(BridgeMethodResolver.findBridgedMethod(bridged)).`as`("Incorrect bridged method returned").isEqualTo(unbridged)
Assertions.assertThat(BridgeMethodResolver.findBridgedMethod(unbridged)).`as`("Unbridged method not returned directly").isEqualTo(unbridged)
Assertions.assertThat(BridgeMethodResolver.findBridgedMethod(bridged)).`as`("Incorrect bridged method returned").isEqualTo(unbridged)
}
}
@@ -1 +0,0 @@
test 1
@@ -1 +0,0 @@
test 2
@@ -16,8 +16,6 @@
package org.springframework.core.testfixture.io.buffer;
import java.time.Duration;
import org.junit.jupiter.api.AfterEach;
import org.springframework.core.io.buffer.DataBufferFactory;
@@ -44,7 +42,7 @@ public abstract class AbstractLeakCheckingTests {
*/
@AfterEach
final void checkForLeaks() {
this.bufferFactory.checkForLeaks(Duration.ofSeconds(1));
this.bufferFactory.checkForLeaks();
}
}
@@ -81,21 +81,13 @@ public class LeakAwareDataBufferFactory implements DataBufferFactory {
* method.
*/
public void checkForLeaks() {
checkForLeaks(Duration.ofSeconds(0));
}
/**
* Variant of {@link #checkForLeaks()} with the option to wait for buffer release.
* @param timeout how long to wait for buffers to be released; 0 for no waiting
*/
public void checkForLeaks(Duration timeout) {
this.trackCreated.set(false);
Instant start = Instant.now();
while (true) {
if (this.created.stream().noneMatch(LeakAwareDataBuffer::isAllocated)) {
return;
}
if (Instant.now().isBefore(start.plus(timeout))) {
if (Instant.now().isBefore(start.plus(Duration.ofSeconds(5)))) {
try {
Thread.sleep(50);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -32,7 +32,6 @@ import org.springframework.util.ObjectUtils;
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.0
*/
public class Elvis extends SpelNodeImpl {
@@ -65,7 +64,7 @@ public class Elvis extends SpelNodeImpl {
@Override
public String toStringAST() {
return "(" + getChild(0).toStringAST() + " ?: " + getChild(1).toStringAST() + ")";
return getChild(0).toStringAST() + " ?: " + getChild(1).toStringAST();
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -32,7 +32,6 @@ import org.springframework.util.ObjectUtils;
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.0
*/
public class Ternary extends SpelNodeImpl {
@@ -63,7 +62,7 @@ public class Ternary extends SpelNodeImpl {
@Override
public String toStringAST() {
return "(" + getChild(0).toStringAST() + " ? " + getChild(1).toStringAST() + " : " + getChild(2).toStringAST() + ")";
return getChild(0).toStringAST() + " ? " + getChild(1).toStringAST() + " : " + getChild(2).toStringAST();
}
private void computeExitTypeDescriptor() {
@@ -116,10 +116,6 @@ class EvaluationTests extends AbstractExpressionTests {
void elvisOperator() {
evaluate("'Andy'?:'Dave'", "Andy", String.class);
evaluate("null?:'Dave'", "Dave", String.class);
evaluate("3?:1", 3, Integer.class);
evaluate("(2*3)?:1*10", 6, Integer.class);
evaluate("null?:2*10", 20, Integer.class);
evaluate("(null?:1)*10", 10, Integer.class);
}
@Test
@@ -628,24 +624,6 @@ class EvaluationTests extends AbstractExpressionTests {
evaluate("2>4?(3>2?true:false):(5<3?true:false)", false, Boolean.class);
}
@Test
void ternaryOperator06() {
evaluate("3?:#var=5", 3, Integer.class);
evaluate("null?:#var=5", 5, Integer.class);
evaluate("2>4?(3>2?true:false):(5<3?true:false)", false, Boolean.class);
}
@Test
void ternaryExpressionWithImplicitGrouping() {
evaluate("4 % 2 == 0 ? 2 : 3 * 10", 2, Integer.class);
evaluate("4 % 2 == 1 ? 2 : 3 * 10", 30, Integer.class);
}
@Test
void ternaryExpressionWithExplicitGrouping() {
evaluate("((4 % 2 == 0) ? 2 : 1) * 10", 20, Integer.class);
}
@Test
void ternaryOperatorWithNullValue() {
assertThatExceptionOfType(EvaluationException.class).isThrownBy(
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -24,380 +24,374 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Parse some expressions and check we get the AST we expect.
*
* <p>Rather than inspecting each node in the AST, we ask it to write itself to
* a string form and check that is as expected.
* Parse some expressions and check we get the AST we expect. Rather than inspecting each node in the AST, we ask it to
* write itself to a string form and check that is as expected.
*
* @author Andy Clement
* @author Sam Brannen
*/
class ParsingTests {
private final SpelExpressionParser parser = new SpelExpressionParser();
public class ParsingTests {
private SpelExpressionParser parser = new SpelExpressionParser();
// literals
@Test
void literalBoolean01() {
public void testLiteralBoolean01() {
parseCheck("false");
}
@Test
void literalLong01() {
public void testLiteralLong01() {
parseCheck("37L", "37");
}
@Test
void literalBoolean02() {
public void testLiteralBoolean02() {
parseCheck("true");
}
@Test
void literalBoolean03() {
public void testLiteralBoolean03() {
parseCheck("!true");
}
@Test
void literalInteger01() {
public void testLiteralInteger01() {
parseCheck("1");
}
@Test
void literalInteger02() {
public void testLiteralInteger02() {
parseCheck("1415");
}
@Test
void literalString01() {
public void testLiteralString01() {
parseCheck("'hello'");
}
@Test
void literalString02() {
public void testLiteralString02() {
parseCheck("'joe bloggs'");
}
@Test
void literalString03() {
public void testLiteralString03() {
parseCheck("'Tony''s Pizza'", "'Tony's Pizza'");
}
@Test
void literalReal01() {
public void testLiteralReal01() {
parseCheck("6.0221415E+23", "6.0221415E23");
}
@Test
void literalHex01() {
public void testLiteralHex01() {
parseCheck("0x7FFFFFFF", "2147483647");
}
@Test
void literalDate01() {
public void testLiteralDate01() {
parseCheck("date('1974/08/24')");
}
@Test
void literalDate02() {
public void testLiteralDate02() {
parseCheck("date('19740824T131030','yyyyMMddTHHmmss')");
}
@Test
void literalNull01() {
public void testLiteralNull01() {
parseCheck("null");
}
// boolean operators
@Test
void booleanOperatorsOr01() {
public void testBooleanOperatorsOr01() {
parseCheck("false or false", "(false or false)");
}
@Test
void booleanOperatorsOr02() {
public void testBooleanOperatorsOr02() {
parseCheck("false or true", "(false or true)");
}
@Test
void booleanOperatorsOr03() {
public void testBooleanOperatorsOr03() {
parseCheck("true or false", "(true or false)");
}
@Test
void booleanOperatorsOr04() {
public void testBooleanOperatorsOr04() {
parseCheck("true or false", "(true or false)");
}
@Test
void booleanOperatorsMix01() {
public void testBooleanOperatorsMix01() {
parseCheck("false or true and false", "(false or (true and false))");
}
// relational operators
@Test
void relOperatorsGT01() {
public void testRelOperatorsGT01() {
parseCheck("3>6", "(3 > 6)");
}
@Test
void relOperatorsLT01() {
public void testRelOperatorsLT01() {
parseCheck("3<6", "(3 < 6)");
}
@Test
void relOperatorsLE01() {
public void testRelOperatorsLE01() {
parseCheck("3<=6", "(3 <= 6)");
}
@Test
void relOperatorsGE01() {
public void testRelOperatorsGE01() {
parseCheck("3>=6", "(3 >= 6)");
}
@Test
void relOperatorsGE02() {
public void testRelOperatorsGE02() {
parseCheck("3>=3", "(3 >= 3)");
}
@Test
void elvis() {
parseCheck("3?:1", "(3 ?: 1)");
parseCheck("(2*3)?:1*10", "((2 * 3) ?: (1 * 10))");
parseCheck("((2*3)?:1)*10", "(((2 * 3) ?: 1) * 10)");
public void testElvis() {
parseCheck("3?:1", "3 ?: 1");
}
// void relOperatorsIn01() {
// public void testRelOperatorsIn01() {
// parseCheck("3 in {1,2,3,4,5}", "(3 in {1,2,3,4,5})");
// }
//
// void relOperatorsBetween01() {
// public void testRelOperatorsBetween01() {
// parseCheck("1 between {1, 5}", "(1 between {1,5})");
// }
// void relOperatorsBetween02() {
// public void testRelOperatorsBetween02() {
// parseCheck("'efg' between {'abc', 'xyz'}", "('efg' between {'abc','xyz'})");
// }// true
@Test
void relOperatorsIs01() {
public void testRelOperatorsIs01() {
parseCheck("'xyz' instanceof int", "('xyz' instanceof int)");
}// false
// void relOperatorsIs02() {
// public void testRelOperatorsIs02() {
// parseCheck("{1, 2, 3, 4, 5} instanceof List", "({1,2,3,4,5} instanceof List)");
// }// true
@Test
void relOperatorsMatches01() {
public void testRelOperatorsMatches01() {
parseCheck("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'", "('5.0067' matches '^-?\\d+(\\.\\d{2})?$')");
}// false
@Test
void relOperatorsMatches02() {
public void testRelOperatorsMatches02() {
parseCheck("'5.00' matches '^-?\\d+(\\.\\d{2})?$'", "('5.00' matches '^-?\\d+(\\.\\d{2})?$')");
}// true
// mathematical operators
@Test
void mathOperatorsAdd01() {
public void testMathOperatorsAdd01() {
parseCheck("2+4", "(2 + 4)");
}
@Test
void mathOperatorsAdd02() {
public void testMathOperatorsAdd02() {
parseCheck("'a'+'b'", "('a' + 'b')");
}
@Test
void mathOperatorsAdd03() {
public void testMathOperatorsAdd03() {
parseCheck("'hello'+' '+'world'", "(('hello' + ' ') + 'world')");
}
@Test
void mathOperatorsSubtract01() {
public void testMathOperatorsSubtract01() {
parseCheck("5-4", "(5 - 4)");
}
@Test
void mathOperatorsMultiply01() {
public void testMathOperatorsMultiply01() {
parseCheck("7*4", "(7 * 4)");
}
@Test
void mathOperatorsDivide01() {
public void testMathOperatorsDivide01() {
parseCheck("8/4", "(8 / 4)");
}
@Test
void mathOperatorModulus01() {
public void testMathOperatorModulus01() {
parseCheck("7 % 4", "(7 % 4)");
}
// mixed operators
@Test
void mixedOperators01() {
public void testMixedOperators01() {
parseCheck("true and 5>3", "(true and (5 > 3))");
}
// collection processors
// void collectionProcessorsCount01() {
// public void testCollectionProcessorsCount01() {
// parseCheck("new String[] {'abc','def','xyz'}.count()");
// }
// void collectionProcessorsCount02() {
// public void testCollectionProcessorsCount02() {
// parseCheck("new int[] {1,2,3}.count()");
// }
//
// void collectionProcessorsMax01() {
// public void testCollectionProcessorsMax01() {
// parseCheck("new int[] {1,2,3}.max()");
// }
//
// void collectionProcessorsMin01() {
// public void testCollectionProcessorsMin01() {
// parseCheck("new int[] {1,2,3}.min()");
// }
//
// void collectionProcessorsAverage01() {
// public void testCollectionProcessorsAverage01() {
// parseCheck("new int[] {1,2,3}.average()");
// }
//
// void collectionProcessorsSort01() {
// public void testCollectionProcessorsSort01() {
// parseCheck("new int[] {3,2,1}.sort()");
// }
//
// void collectionProcessorsNonNull01() {
// public void testCollectionProcessorsNonNull01() {
// parseCheck("{'a','b',null,'d',null}.nonNull()");
// }
//
// void collectionProcessorsDistinct01() {
// public void testCollectionProcessorsDistinct01() {
// parseCheck("{'a','b','a','d','e'}.distinct()");
// }
// references
@Test
void references01() {
public void testReferences01() {
parseCheck("@foo");
parseCheck("@'foo.bar'");
parseCheck("@\"foo.bar.goo\"" , "@'foo.bar.goo'");
parseCheck("@\"foo.bar.goo\"","@'foo.bar.goo'");
}
@Test
void references03() {
public void testReferences03() {
parseCheck("@$$foo");
}
// properties
@Test
void properties01() {
public void testProperties01() {
parseCheck("name");
}
@Test
void properties02() {
public void testProperties02() {
parseCheck("placeofbirth.CitY");
}
@Test
void properties03() {
public void testProperties03() {
parseCheck("a.b.c.d.e");
}
// inline list creation
@Test
void inlineListCreation01() {
public void testInlineListCreation01() {
parseCheck("{1, 2, 3, 4, 5}", "{1,2,3,4,5}");
}
@Test
void inlineListCreation02() {
public void testInlineListCreation02() {
parseCheck("{'abc','xyz'}", "{'abc','xyz'}");
}
// inline map creation
@Test
void inlineMapCreation01() {
public void testInlineMapCreation01() {
parseCheck("{'key1':'Value 1','today':DateTime.Today}");
}
@Test
void inlineMapCreation02() {
public void testInlineMapCreation02() {
parseCheck("{1:'January',2:'February',3:'March'}");
}
// methods
@Test
void methods01() {
public void testMethods01() {
parseCheck("echo(12)");
}
@Test
void methods02() {
public void testMethods02() {
parseCheck("echo(name)");
}
@Test
void methods03() {
public void testMethods03() {
parseCheck("age.doubleItAndAdd(12)");
}
// constructors
@Test
void constructors01() {
public void testConstructors01() {
parseCheck("new String('hello')");
}
// void constructors02() {
// public void testConstructors02() {
// parseCheck("new String[3]");
// }
// array construction
// void arrayConstruction01() {
// public void testArrayConstruction01() {
// parseCheck("new int[] {1, 2, 3, 4, 5}", "new int[] {1,2,3,4,5}");
// }
//
// void arrayConstruction02() {
// public void testArrayConstruction02() {
// parseCheck("new String[] {'abc','xyz'}", "new String[] {'abc','xyz'}");
// }
// variables and functions
@Test
void variables01() {
public void testVariables01() {
parseCheck("#foo");
}
@Test
void functions01() {
public void testFunctions01() {
parseCheck("#fn(1,2,3)");
}
@Test
void functions02() {
public void testFunctions02() {
parseCheck("#fn('hello')");
}
// projections and selections
// void projections01() {
// public void testProjections01() {
// parseCheck("{1,2,3,4,5,6,7,8,9,10}.!{#isEven()}");
// }
// void selections01() {
// public void testSelections01() {
// parseCheck("{1,2,3,4,5,6,7,8,9,10}.?{#isEven(#this) == 'y'}",
// "{1,2,3,4,5,6,7,8,9,10}.?{(#isEven(#this) == 'y')}");
// }
// void selectionsFirst01() {
// public void testSelectionsFirst01() {
// parseCheck("{1,2,3,4,5,6,7,8,9,10}.^{#isEven(#this) == 'y'}",
// "{1,2,3,4,5,6,7,8,9,10}.^{(#isEven(#this) == 'y')}");
// }
// void selectionsLast01() {
// public void testSelectionsLast01() {
// parseCheck("{1,2,3,4,5,6,7,8,9,10}.${#isEven(#this) == 'y'}",
// "{1,2,3,4,5,6,7,8,9,10}.${(#isEven(#this) == 'y')}");
// }
// assignment
@Test
void assignmentToVariables01() {
public void testAssignmentToVariables01() {
parseCheck("#var1='value1'");
}
@@ -405,43 +399,38 @@ class ParsingTests {
// ternary operator
@Test
void ternaryOperator01() {
parseCheck("1>2?3:4", "((1 > 2) ? 3 : 4)");
parseCheck("(a ? 1 : 0) * 10", "((a ? 1 : 0) * 10)");
parseCheck("(a?1:0)*10", "((a ? 1 : 0) * 10)");
parseCheck("(4 % 2 == 0 ? 1 : 0) * 10", "((((4 % 2) == 0) ? 1 : 0) * 10)");
parseCheck("((4 % 2 == 0) ? 1 : 0) * 10", "((((4 % 2) == 0) ? 1 : 0) * 10)");
public void testTernaryOperator01() {
parseCheck("1>2?3:4","(1 > 2) ? 3 : 4");
}
@Test
void ternaryOperator02() {
parseCheck("{1}.#isEven(#this) == 'y'?'it is even':'it is odd'",
"(({1}.#isEven(#this) == 'y') ? 'it is even' : 'it is odd')");
}
// public void testTernaryOperator01() {
// parseCheck("{1}.#isEven(#this) == 'y'?'it is even':'it is odd'",
// "({1}.#isEven(#this) == 'y') ? 'it is even' : 'it is odd'");
// }
//
// void lambdaMax() {
// public void testLambdaMax() {
// parseCheck("(#max = {|x,y| $x > $y ? $x : $y }; #max(5,25))", "(#max={|x,y| ($x > $y) ? $x : $y };#max(5,25))");
// }
//
// void lambdaFactorial() {
// public void testLambdaFactorial() {
// parseCheck("(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #fact(5))",
// "(#fact={|n| ($n <= 1) ? 1 : ($n * #fact(($n - 1))) };#fact(5))");
// } // 120
// Type references
@Test
void typeReferences01() {
public void testTypeReferences01() {
parseCheck("T(java.lang.String)");
}
@Test
void typeReferences02() {
public void testTypeReferences02() {
parseCheck("T(String)");
}
@Test
void inlineList1() {
public void testInlineList1() {
parseCheck("{1,2,3,4}");
}
@@ -451,7 +440,7 @@ class ParsingTests {
*
* @param expression the expression to parse *and* the expected value of the string form of the resultant AST
*/
private void parseCheck(String expression) {
public void parseCheck(String expression) {
parseCheck(expression, expression);
}
@@ -462,7 +451,7 @@ class ParsingTests {
* @param expression the expression to parse
* @param expectedStringFormOfAST the expected string form of the AST
*/
private void parseCheck(String expression, String expectedStringFormOfAST) {
public void parseCheck(String expression, String expectedStringFormOfAST) {
SpelExpression e = parser.parseRaw(expression);
assertThat(e).isNotNull();
assertThat(e.toStringAST()).isEqualTo(expectedStringFormOfAST);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -78,9 +78,9 @@ public abstract class NamedParameterUtils {
* Parse the SQL statement and locate any placeholders or named parameters.
* Named parameters are substituted for a JDBC placeholder.
* @param sql the SQL statement
* @return the parsed statement, represented as {@link ParsedSql} instance
* @return the parsed statement, represented as ParsedSql instance
*/
public static ParsedSql parseSqlStatement(String sql) {
public static ParsedSql parseSqlStatement(final String sql) {
Assert.notNull(sql, "SQL must not be null");
Set<String> namedParameters = new HashSet<>();
@@ -122,20 +122,17 @@ public abstract class NamedParameterUtils {
while (statement[j] != '}') {
j++;
if (j >= statement.length) {
throw new InvalidDataAccessApiUsageException(
"Non-terminated named parameter declaration at position " + i +
" in statement: " + sql);
throw new InvalidDataAccessApiUsageException("Non-terminated named parameter declaration " +
"at position " + i + " in statement: " + sql);
}
if (statement[j] == ':' || statement[j] == '{') {
throw new InvalidDataAccessApiUsageException(
"Parameter name contains invalid character '" + statement[j] +
"' at position " + i + " in statement: " + sql);
throw new InvalidDataAccessApiUsageException("Parameter name contains invalid character '" +
statement[j] + "' at position " + i + " in statement: " + sql);
}
}
if (j - i > 2) {
parameter = sql.substring(i + 2, j);
namedParameterCount = addNewNamedParameter(
namedParameters, namedParameterCount, parameter);
namedParameterCount = addNewNamedParameter(namedParameters, namedParameterCount, parameter);
totalParameterCount = addNamedParameter(
parameterList, totalParameterCount, escapes, i, j + 1, parameter);
}
@@ -147,8 +144,7 @@ public abstract class NamedParameterUtils {
}
if (j - i > 1) {
parameter = sql.substring(i + 1, j);
namedParameterCount = addNewNamedParameter(
namedParameters, namedParameterCount, parameter);
namedParameterCount = addNewNamedParameter(namedParameters, namedParameterCount, parameter);
totalParameterCount = addNamedParameter(
parameterList, totalParameterCount, escapes, i, j, parameter);
}
@@ -189,8 +185,8 @@ public abstract class NamedParameterUtils {
return parsedSql;
}
private static int addNamedParameter(List<ParameterHolder> parameterList,
int totalParameterCount, int escapes, int i, int j, String parameter) {
private static int addNamedParameter(
List<ParameterHolder> parameterList, int totalParameterCount, int escapes, int i, int j, String parameter) {
parameterList.add(new ParameterHolder(parameter, i - escapes, j - escapes));
totalParameterCount++;
@@ -275,7 +271,6 @@ public abstract class NamedParameterUtils {
if (paramNames.isEmpty()) {
return originalSql;
}
StringBuilder actualSql = new StringBuilder(originalSql.length());
int lastIndex = 0;
for (int i = 0; i < paramNames.size(); i++) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -319,29 +319,4 @@ public class NamedParameterUtilsTests {
assertThat(psql2.getParameterNames().get(0)).isEqualTo("xxx");
}
@Test // gh-27925
void namedParamMapReference() {
String sql = "insert into foos (id) values (:headers[id])";
ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql);
assertThat(psql.getNamedParameterCount()).isEqualTo(1);
assertThat(psql.getParameterNames()).containsExactly("headers[id]");
class Foo {
final Map<String, Object> headers = new HashMap<>();
public Foo() {
this.headers.put("id", 1);
}
public Map<String, Object> getHeaders() {
return this.headers;
}
}
Foo foo = new Foo();
Object[] params = NamedParameterUtils.buildValueArray(psql,
new BeanPropertySqlParameterSource(foo), null);
assertThat(params[0]).isInstanceOf(SqlParameterValue.class);
assertThat(((SqlParameterValue) params[0]).getValue()).isEqualTo(foo.getHeaders().get("id"));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors
* Copyright 2002-2021 the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
package org.springframework.jdbc.core
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
import org.springframework.jdbc.core.test.ConstructorPerson
import java.math.BigDecimal
@@ -31,7 +31,7 @@ class KotlinDataClassRowMapperTests : AbstractRowMapperTests() {
"select name, age, birth_date, balance from people",
DataClassRowMapper(ConstructorPerson::class.java)
)
assertThat(result.size).isEqualTo(1)
Assertions.assertThat(result.size).isEqualTo(1)
verifyPerson(result[0])
mock.verifyClosed()
}
@@ -43,8 +43,8 @@ class KotlinDataClassRowMapperTests : AbstractRowMapperTests() {
"select name, age, birth_date, balance from people",
DataClassRowMapper(KotlinPerson::class.java)
)
assertThat(result.size).isEqualTo(1)
assertThat(result[0].name).isEqualTo("Bubba appended by init")
Assertions.assertThat(result.size).isEqualTo(1)
Assertions.assertThat(result[0].name).isEqualTo("Bubba appended by init")
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -103,7 +103,7 @@ final class DefaultRSocketRequesterBuilder implements RSocketRequester.Builder {
@Override
public RSocketRequester.Builder metadataMimeType(MimeType mimeType) {
Assert.notNull(mimeType, "'metadataMimeType' is required");
Assert.notNull(mimeType, "`metadataMimeType` is required");
this.metadataMimeType = mimeType;
return this;
}
@@ -281,7 +281,7 @@ final class DefaultRSocketRequesterBuilder implements RSocketRequester.Builder {
Mono<DataBuffer> dataMono = Mono.empty();
if (data != null) {
ReactiveAdapter adapter = strategies.reactiveAdapterRegistry().getAdapter(data.getClass());
Assert.isTrue(adapter == null || !adapter.isMultiValue(), () -> "Expected single value: " + data);
Assert.isTrue(adapter == null || !adapter.isMultiValue(), "Expected single value: " + data);
Mono<?> mono = (adapter != null ? Mono.from(adapter.toPublisher(data)) : Mono.just(data));
dataMono = mono.map(value -> {
ResolvableType type = ResolvableType.forClass(value.getClass());
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -141,8 +141,7 @@ final class MetadataEncoder {
}
ReactiveAdapter adapter = this.strategies.reactiveAdapterRegistry().getAdapter(metadata.getClass());
if (adapter != null) {
Object originalMetadata = metadata;
Assert.isTrue(!adapter.isMultiValue(), () -> "Expected single value: " + originalMetadata);
Assert.isTrue(!adapter.isMultiValue(), "Expected single value: " + metadata);
metadata = Mono.from(adapter.toPublisher(metadata)).defaultIfEmpty(NO_VALUE);
this.hasAsyncValues = true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -421,7 +421,7 @@ public class RSocketMessageHandler extends MessageMappingMessageHandler {
String str = setupPayload.dataMimeType();
MimeType dataMimeType = StringUtils.hasText(str) ? MimeTypeUtils.parseMimeType(str) : this.defaultDataMimeType;
Assert.notNull(dataMimeType, "No `dataMimeType` in ConnectionSetupPayload and no default value");
Assert.isTrue(isDataMimeTypeSupported(dataMimeType), () -> "Data MimeType '" + dataMimeType + "' not supported");
Assert.isTrue(isDataMimeTypeSupported(dataMimeType), "Data MimeType '" + dataMimeType + "' not supported");
str = setupPayload.metadataMimeType();
MimeType metaMimeType = StringUtils.hasText(str) ? MimeTypeUtils.parseMimeType(str) : this.defaultMetadataMimeType;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -138,7 +138,7 @@ public class SimpMessagingTemplate extends AbstractMessageSendingTemplate<String
*/
@Override
public void send(Message<?> message) {
Assert.notNull(message, "Message must not be null");
Assert.notNull(message, "Message is required");
String destination = SimpMessageHeaderAccessor.getDestination(message.getHeaders());
if (destination != null) {
sendInternal(message);
@@ -224,8 +224,7 @@ public class SimpMessagingTemplate extends AbstractMessageSendingTemplate<String
throws MessagingException {
Assert.notNull(user, "User must not be null");
String username = user;
Assert.isTrue(!user.contains("%2F"), () -> "Invalid sequence \"%2F\" in user name: " + username);
Assert.isTrue(!user.contains("%2F"), "Invalid sequence \"%2F\" in user name: " + user);
user = StringUtils.replace(user, "/", "%2F");
destination = destination.startsWith("/") ? destination : "/" + destination;
super.convertAndSend(this.destinationPrefix + user + destination, payload, headers, postProcessor);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -148,7 +148,7 @@ public class OrderedMessageChannelDecorator implements MessageChannel {
public static void configureInterceptor(MessageChannel channel, boolean preserveOrder) {
if (preserveOrder) {
Assert.isInstanceOf(ExecutorSubscribableChannel.class, channel,
"An ExecutorSubscribableChannel is required for 'preservePublishOrder'");
"An ExecutorSubscribableChannel is required for `preservePublishOrder`");
ExecutorSubscribableChannel execChannel = (ExecutorSubscribableChannel) channel;
if (execChannel.getInterceptors().stream().noneMatch(i -> i instanceof CallbackInterceptor)) {
execChannel.addInterceptor(0, new CallbackInterceptor());
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -264,12 +264,9 @@ public class StompDecoder {
* <a href="https://stomp.github.io/stomp-specification-1.2.html#Value_Encoding">"Value Encoding"</a>.
*/
private String unescape(String inString) {
int index = inString.indexOf('\\');
if (index == -1) {
return inString;
}
StringBuilder sb = new StringBuilder(inString.length());
int pos = 0; // position in the old string
int index = inString.indexOf('\\');
while (index >= 0) {
sb.append(inString, pos, index);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -211,7 +211,7 @@ public class StompHeaders implements MultiValueMap<String, String>, Serializable
}
Arrays.stream(acceptVersions).forEach(version ->
Assert.isTrue(version != null && (version.equals("1.1") || version.equals("1.2")),
() -> "Invalid version: " + version));
"Invalid version: " + version));
set(ACCEPT_VERSION, StringUtils.arrayToCommaDelimitedString(acceptVersions));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -203,7 +203,7 @@ public class DefaultUserDestinationResolver implements UserDestinationResolver {
}
Principal principal = SimpMessageHeaderAccessor.getUser(headers);
String user = (principal != null ? principal.getName() : null);
Assert.isTrue(user == null || !user.contains("%2F"), () -> "Invalid sequence \"%2F\" in user name: " + user);
Assert.isTrue(user == null || !user.contains("%2F"), "Invalid sequence \"%2F\" in user name: " + user);
Set<String> sessionIds = Collections.singleton(sessionId);
return new ParseResult(sourceDestination, actualDestination, sourceDestination, sessionIds, user);
}
@@ -43,7 +43,7 @@ import org.springframework.util.StringUtils;
* strongly typed accessors for specific headers, the ability to leave headers
* in a {@link Message} mutable, and the option to suppress automatic generation
* of {@link MessageHeaders#ID id} and {@link MessageHeaders#TIMESTAMP
* timestamp} headers. Subclasses such as {@link NativeMessageHeaderAccessor}
* timesteamp} headers. Subclasses such as {@link NativeMessageHeaderAccessor}
* and others provide support for managing processing vs external source headers
* as well as protocol specific headers.
*
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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,8 +17,7 @@
package org.springframework.messaging.converter
import kotlinx.serialization.Serializable
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
import org.springframework.core.MethodParameter
import org.springframework.messaging.support.MessageBuilder
@@ -51,12 +50,12 @@ class KotlinSerializationJsonMessageConverterTests {
val message = MessageBuilder.withPayload(payload.toByteArray(StandardCharsets.UTF_8)).build()
val result = converter.fromMessage(message, SerializableBean::class.java) as SerializableBean
assertThat(result.bytes).containsExactly(0x1, 0x2)
assertThat(result.array).containsExactly("Foo", "Bar")
assertThat(result.number).isEqualTo(42)
assertThat(result.string).isEqualTo("Foo")
assertThat(result.bool).isTrue()
assertThat(result.fraction).isEqualTo(42.0f)
Assertions.assertThat(result.bytes).containsExactly(0x1, 0x2)
Assertions.assertThat(result.array).containsExactly("Foo", "Bar")
Assertions.assertThat(result.number).isEqualTo(42)
Assertions.assertThat(result.string).isEqualTo("Foo")
Assertions.assertThat(result.bool).isTrue()
Assertions.assertThat(result.fraction).isEqualTo(42.0f)
}
@Test
@@ -83,13 +82,13 @@ class KotlinSerializationJsonMessageConverterTests {
val message = MessageBuilder.withPayload(payload.toByteArray(StandardCharsets.UTF_8)).build()
val result = converter.fromMessage(message, Array<SerializableBean>::class.java) as Array<SerializableBean>
assertThat(result).hasSize(1)
assertThat(result[0].bytes).containsExactly(0x1, 0x2)
assertThat(result[0].array).containsExactly("Foo", "Bar")
assertThat(result[0].number).isEqualTo(42)
assertThat(result[0].string).isEqualTo("Foo")
assertThat(result[0].bool).isTrue()
assertThat(result[0].fraction).isEqualTo(42.0f)
Assertions.assertThat(result).hasSize(1)
Assertions.assertThat(result[0].bytes).containsExactly(0x1, 0x2)
Assertions.assertThat(result[0].array).containsExactly("Foo", "Bar")
Assertions.assertThat(result[0].number).isEqualTo(42)
Assertions.assertThat(result[0].string).isEqualTo("Foo")
Assertions.assertThat(result[0].bool).isTrue()
Assertions.assertThat(result[0].fraction).isEqualTo(42.0f)
}
@Test
@@ -119,13 +118,13 @@ class KotlinSerializationJsonMessageConverterTests {
val message = MessageBuilder.withPayload(payload.toByteArray(StandardCharsets.UTF_8)).build()
val result = converter.fromMessage(message, typeOf<List<SerializableBean>>()::class.java, param) as List<SerializableBean>
assertThat(result).hasSize(1)
assertThat(result[0].bytes).containsExactly(0x1, 0x2)
assertThat(result[0].array).containsExactly("Foo", "Bar")
assertThat(result[0].number).isEqualTo(42)
assertThat(result[0].string).isEqualTo("Foo")
assertThat(result[0].bool).isTrue()
assertThat(result[0].fraction).isEqualTo(42.0f)
Assertions.assertThat(result).hasSize(1)
Assertions.assertThat(result[0].bytes).containsExactly(0x1, 0x2)
Assertions.assertThat(result[0].array).containsExactly("Foo", "Bar")
Assertions.assertThat(result[0].number).isEqualTo(42)
Assertions.assertThat(result[0].string).isEqualTo("Foo")
Assertions.assertThat(result[0].bool).isTrue()
Assertions.assertThat(result[0].fraction).isEqualTo(42.0f)
}
@Test
@@ -135,7 +134,7 @@ class KotlinSerializationJsonMessageConverterTests {
""".trimIndent()
val message = MessageBuilder.withPayload(payload.toByteArray(StandardCharsets.UTF_8)).build()
assertThatExceptionOfType(MessageConversionException::class.java).isThrownBy {
Assertions.assertThatExceptionOfType(MessageConversionException::class.java).isThrownBy {
converter.fromMessage(message, SerializableBean::class.java)
}
}
@@ -146,7 +145,7 @@ class KotlinSerializationJsonMessageConverterTests {
val message = converter.toMessage(serializableBean, null)
val result = String((message!!.payload as ByteArray), StandardCharsets.UTF_8)
assertThat(result)
Assertions.assertThat(result)
.contains("\"bytes\":[1,2]")
.contains("\"array\":[\"Foo\",\"Bar\"]")
.contains("\"number\":42")
@@ -161,7 +160,7 @@ class KotlinSerializationJsonMessageConverterTests {
val message = converter.toMessage(serializableBean, null)
val result = String((message!!.payload as ByteArray), StandardCharsets.UTF_8)
assertThat(result)
Assertions.assertThat(result)
.contains("\"bytes\":[1,2]")
.contains("\"array\":[\"Foo\",\"Bar\"]")
.contains("\"number\":42")
@@ -180,7 +179,7 @@ class KotlinSerializationJsonMessageConverterTests {
val message = converter.toMessage(arrayOf(serializableBean), null)
val result = String((message!!.payload as ByteArray), StandardCharsets.UTF_8)
assertThat(result).isEqualTo(expectedJson)
Assertions.assertThat(result).isEqualTo(expectedJson)
}
@Test
@@ -196,7 +195,7 @@ class KotlinSerializationJsonMessageConverterTests {
val message = converter.toMessage(arrayListOf(serializableBean), null, param)
val result = String((message!!.payload as ByteArray), StandardCharsets.UTF_8)
assertThat(result).isEqualTo(expectedJson)
Assertions.assertThat(result).isEqualTo(expectedJson)
}
@Suppress("UNUSED_PARAMETER")
@@ -144,7 +144,7 @@ public interface DatabaseClient extends ConnectionAccessor {
Builder apply(Consumer<Builder> builderConsumer);
/**
* Build the {@link DatabaseClient} instance.
* Builder the {@link DatabaseClient} instance.
*/
DatabaseClient build();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -273,7 +273,7 @@ class DefaultDatabaseClient implements DatabaseClient {
public DefaultGenericExecuteSpec bind(String name, Object value) {
assertNotPreparedOperation();
Assert.hasText(name, "Parameter name must not be null or empty");
Assert.hasText(name, "Parameter name must not be null or empty!");
Assert.notNull(value, () -> String.format(
"Value for parameter %s must not be null. Use bindNull(…) instead.", name));
@@ -291,7 +291,7 @@ class DefaultDatabaseClient implements DatabaseClient {
@Override
public DefaultGenericExecuteSpec bindNull(String name, Class<?> type) {
assertNotPreparedOperation();
Assert.hasText(name, "Parameter name must not be null or empty");
Assert.hasText(name, "Parameter name must not be null or empty!");
Map<String, Parameter> byName = new LinkedHashMap<>(this.byName);
byName.put(name, Parameter.empty(type));
@@ -301,7 +301,7 @@ class DefaultDatabaseClient implements DatabaseClient {
@Override
public DefaultGenericExecuteSpec filter(StatementFilterFunction filter) {
Assert.notNull(filter, "StatementFilterFunction must not be null");
Assert.notNull(filter, "Statement FilterFunction must not be null");
return new DefaultGenericExecuteSpec(
this.byIndex, this.byName, this.sqlSupplier, this.filterFunction.andThen(filter));
}
@@ -449,7 +449,7 @@ class DefaultDatabaseClient implements DatabaseClient {
private String getRequiredSql(Supplier<String> sqlSupplier) {
String sql = sqlSupplier.get();
Assert.state(StringUtils.hasText(sql), "SQL returned by supplier must not be empty");
Assert.state(StringUtils.hasText(sql), "SQL returned by SQL supplier must not be empty!");
return sql;
}
}
@@ -37,7 +37,8 @@ import org.springframework.util.Assert;
/**
* Helper methods for named parameter parsing.
*
* <p>Only intended for internal use within Spring's R2DBC framework.
* <p>Only intended for internal use within Spring's R2DBC
* framework.
*
* <p>References to the same parameter name are substituted with
* the same bind marker placeholder if a {@link BindMarkersFactory} uses
@@ -292,6 +293,7 @@ abstract class NamedParameterUtils {
if (paramSource.hasValue(paramName)) {
Object value = paramSource.getValue(paramName);
if (value instanceof Collection) {
Iterator<?> entryIter = ((Collection<?>) value).iterator();
int k = 0;
int counter = 0;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -43,7 +43,6 @@ public class NamedParameterUtilsUnitTests {
private final BindMarkersFactory BIND_MARKERS = BindMarkersFactory.indexed("$", 1);
@Test
public void shouldParseSql() {
String sql = "xxx :a yyyy :b :c :a zzzzz";
@@ -146,6 +145,7 @@ public class NamedParameterUtilsUnitTests {
String sql = "select 'first name' from artists where info->'stat'->'albums' = ?? :album and '[\"1\",\"2\",\"3\"]'::jsonb ?? '4'";
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
assertThat(parsedSql.getTotalParameterCount()).isEqualTo(1);
assertThat(expand(parsedSql)).isEqualTo(expectedSql);
}
@@ -156,6 +156,7 @@ public class NamedParameterUtilsUnitTests {
String sql = "select '[\"3\", \"11\"]'::jsonb ?| '{1,3,11,12,17}'::text[]";
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
assertThat(parsedSql.getTotalParameterCount()).isEqualTo(0);
assertThat(expand(parsedSql)).isEqualTo(expectedSql);
}
@@ -176,6 +177,7 @@ public class NamedParameterUtilsUnitTests {
String sql = "select '0\\:0' as a, foo from bar where baz < DATE(:p1 23\\:59\\:59) and baz = :p2";
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
assertThat(parsedSql.getParameterNames()).containsExactly("p1", "p2");
assertThat(expand(parsedSql)).isEqualTo(expectedSql);
}
@@ -196,6 +198,7 @@ public class NamedParameterUtilsUnitTests {
String sql = "select foo from bar where baz = b:{}z";
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
assertThat(parsedSql.getParameterNames()).isEmpty();
assertThat(expand(parsedSql)).isEqualTo(expectedSql);
@@ -222,11 +225,13 @@ public class NamedParameterUtilsUnitTests {
String expectedSql = "xxx & yyyy";
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(expectedSql);
assertThat(expand(parsedSql)).isEqualTo(expectedSql);
}
@Test
public void substituteNamedParametersWithLogicalAnd() {
String expectedSql = "xxx & yyyy";
assertThat(expand(expectedSql)).isEqualTo(expectedSql);
@@ -244,6 +249,7 @@ public class NamedParameterUtilsUnitTests {
String sql = "SELECT ':foo'':doo', :xxx FROM DUAL";
ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql);
assertThat(psql.getTotalParameterCount()).isEqualTo(1);
assertThat(psql.getParameterNames()).containsExactly("xxx");
}
@@ -253,6 +259,7 @@ public class NamedParameterUtilsUnitTests {
String sql = "SELECT /*:doo*/':foo', :xxx FROM DUAL";
ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql);
assertThat(psql.getTotalParameterCount()).isEqualTo(1);
assertThat(psql.getParameterNames()).containsExactly("xxx");
}
@@ -262,23 +269,18 @@ public class NamedParameterUtilsUnitTests {
String sql2 = "SELECT ':foo'/*:doo*/, :xxx FROM DUAL";
ParsedSql psql2 = NamedParameterUtils.parseSqlStatement(sql2);
assertThat(psql2.getTotalParameterCount()).isEqualTo(1);
assertThat(psql2.getParameterNames()).containsExactly("xxx");
}
@Test // gh-27925
void namedParamMapReference() {
String sql = "insert into foos (id) values (:headers[id])";
ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql);
assertThat(psql.getNamedParameterCount()).isEqualTo(1);
assertThat(psql.getParameterNames()).containsExactly("headers[id]");
}
@Test
public void shouldAllowParsingMultipleUseOfParameter() {
String sql = "SELECT * FROM person where name = :id or lastname = :id";
ParsedSql parsed = NamedParameterUtils.parseSqlStatement(sql);
assertThat(parsed.getTotalParameterCount()).isEqualTo(2);
assertThat(parsed.getNamedParameterCount()).isEqualTo(1);
assertThat(parsed.getParameterNames()).containsExactly("id", "id");
@@ -298,19 +300,23 @@ public class NamedParameterUtilsUnitTests {
"SELECT * FROM person where name = $0 or lastname = $0");
operation.bindTo(new BindTarget() {
@Override
public void bind(String identifier, Object value) {
throw new UnsupportedOperationException();
}
@Override
public void bind(int index, Object value) {
assertThat(index).isEqualTo(0);
assertThat(value).isEqualTo("foo");
}
@Override
public void bindNull(String identifier, Class<?> type) {
throw new UnsupportedOperationException();
}
@Override
public void bindNull(int index, Class<?> type) {
throw new UnsupportedOperationException();
@@ -334,20 +340,25 @@ public class NamedParameterUtilsUnitTests {
"SELECT * FROM person where name IN ($0, $1, $2) or lastname IN ($0, $1, $2)");
operation.bindTo(new BindTarget() {
@Override
public void bind(String identifier, Object value) {
throw new UnsupportedOperationException();
}
@Override
public void bind(int index, Object value) {
assertThat(index).isIn(0, 1, 2);
assertThat(value).isIn("foo", "bar", "baz");
bindings.add(index, value);
}
@Override
public void bindNull(String identifier, Class<?> type) {
throw new UnsupportedOperationException();
}
@Override
public void bindNull(int index, Class<?> type) {
throw new UnsupportedOperationException();
@@ -375,18 +386,22 @@ public class NamedParameterUtilsUnitTests {
Map<Integer, Object> bindValues = new LinkedHashMap<>();
operation.bindTo(new BindTarget() {
@Override
public void bind(String identifier, Object value) {
throw new UnsupportedOperationException();
}
@Override
public void bind(int index, Object value) {
bindValues.put(index, value);
}
@Override
public void bindNull(String identifier, Class<?> type) {
throw new UnsupportedOperationException();
}
@Override
public void bindNull(int index, Class<?> type) {
throw new UnsupportedOperationException();
@@ -410,18 +425,22 @@ public class NamedParameterUtilsUnitTests {
"SELECT * FROM person where name = $0 or lastname = $0");
operation.bindTo(new BindTarget() {
@Override
public void bind(String identifier, Object value) {
throw new UnsupportedOperationException();
}
@Override
public void bind(int index, Object value) {
throw new UnsupportedOperationException();
}
@Override
public void bindNull(String identifier, Class<?> type) {
throw new UnsupportedOperationException();
}
@Override
public void bindNull(int index, Class<?> type) {
assertThat(index).isEqualTo(0);
@@ -430,7 +449,6 @@ public class NamedParameterUtilsUnitTests {
});
}
private String expand(ParsedSql sql) {
return NamedParameterUtils.substituteNamedParameters(sql, BIND_MARKERS,
new MapBindParameterSource()).toQuery();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -77,7 +77,7 @@ import org.springframework.util.StringUtils;
* is {@link Locale#ENGLISH}. This value can be changed via {@link #addPreferredLocale}
* or {@link #setPreferredLocales}.
*
* <p>As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
* <p>As of Spring Framework 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
*
* @author Juergen Hoeller
* @author Rod Johnson
@@ -53,7 +53,7 @@ import org.springframework.web.util.WebUtils;
/**
* Mock implementation of the {@link javax.servlet.http.HttpServletResponse} interface.
*
* <p>As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
* <p>As of Spring Framework 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
*
* @author Juergen Hoeller
* @author Rod Johnson
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -84,7 +84,7 @@ public class PassThroughFilterChain implements FilterChain {
this.filter.doFilter(request, response, this.nextFilterChain);
}
else {
Assert.state(this.servlet != null, "Neither a Filter nor a Servlet has been set");
Assert.state(this.servlet != null, "Neither a Filter not a Servlet set");
this.servlet.service(request, response);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -41,24 +41,8 @@ package org.springframework.test.context;
* {@link org.springframework.core.annotation.Order @Order} annotation. See
* {@link TestContextBootstrapper#getTestExecutionListeners()} for details.
*
* <h3>Registering TestExecutionListener Implementations</h3>
*
* <p>A {@code TestExecutionListener} can be registered explicitly for a test class,
* its subclasses, and its nested classes by using the
* {@link TestExecutionListeners @TestExecutionListeners} annotation. Explicit
* registration is suitable for custom listeners that are used in limited testing
* scenarios. However, it can become cumbersome if a custom listener needs to be
* used across an entire test suite. This issue is addressed through support for
* automatic discovery of <em>default</em> {@code TestExecutionListener}
* implementations through the
* {@link org.springframework.core.io.support.SpringFactoriesLoader SpringFactoriesLoader}
* mechanism. Specifically, default {@code TestExecutionListener} implementations
* can be registered under the {@code org.springframework.test.context.TestExecutionListener}
* key in a {@code META-INF/spring.factories} properties file.
*
* <p>Spring provides the following implementations. Each of these implements
* {@code Ordered} and is registered automatically by default.
*
* <p>Spring provides the following out-of-the-box implementations (all of
* which implement {@code Ordered}):
* <ul>
* <li>{@link org.springframework.test.context.web.ServletTestExecutionListener
* ServletTestExecutionListener}</li>
@@ -30,30 +30,16 @@ import org.springframework.core.annotation.AliasFor;
* which {@link TestExecutionListener TestExecutionListeners} should be
* registered with a {@link TestContextManager}.
*
* <p>{@code @TestExecutionListeners} is used to register listeners for a
* particular test class, its subclasses, and its nested classes. If you wish to
* register a listener globally, you should register it via the automatic discovery
* mechanism described in {@link TestExecutionListener}.
* <p>Typically, {@code @TestExecutionListeners} will be used in conjunction
* with {@link ContextConfiguration @ContextConfiguration}.
*
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
* <em>composed annotations</em>. As of Spring Framework 5.3, this annotation will
* be inherited from an enclosing test class by default. See
* <em>composed annotations</em>.
*
* <p>As of Spring Framework 5.3, this annotation will be inherited from an
* enclosing test class by default. See
* {@link NestedTestConfiguration @NestedTestConfiguration} for details.
*
* <h3>Switching to default {@code TestExecutionListener} implementations</h3>
*
* <p>If you extend a class that is annotated with {@code @TestExecutionListeners}
* and you need to switch to using the <em>default</em> set of listeners, you
* can annotate your class with the following.
*
* <pre class="code">
* // Switch to default listeners
* &#064;TestExecutionListeners(listeners = {}, inheritListeners = false, mergeMode = MERGE_WITH_DEFAULTS)
* class MyTests extends BaseTests {
* // ...
* }
* </pre>
*
* @author Sam Brannen
* @since 2.5
* @see TestExecutionListener
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -49,10 +49,8 @@ import org.springframework.test.context.web.ServletTestExecutionListener;
* the appropriate {@link org.springframework.test.context.TestExecutionListener
* TestExecutionListeners} manually.</em>
*
* <p>This class explicitly registers the following {@code TestExecutionListener}
* implementations. If you want to switch to using the <em>default</em> set of
* listeners, see the class-level Javadoc for
* {@link TestExecutionListeners @TestExecutionListeners} for details.
* <p>The following {@link org.springframework.test.context.TestExecutionListener
* TestExecutionListeners} are configured by default:
*
* <ul>
* <li>{@link org.springframework.test.context.web.ServletTestExecutionListener}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -57,10 +57,8 @@ import org.springframework.util.Assert;
* <p>Concrete subclasses must fulfill the same requirements outlined in
* {@link AbstractJUnit4SpringContextTests}.
*
* <p>This class explicitly registers the following {@code TestExecutionListener}
* implementations. If you want to switch to using the <em>default</em> set of
* listeners, see the class-level Javadoc for
* {@link TestExecutionListeners @TestExecutionListeners} for details.
* <p>The following {@link org.springframework.test.context.TestExecutionListener
* TestExecutionListeners} are configured by default:
*
* <ul>
* <li>{@link org.springframework.test.context.web.ServletTestExecutionListener}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -59,10 +59,8 @@ import org.springframework.test.context.web.ServletTestExecutionListener;
* TestExecutionListeners} manually.</em> Concrete subclasses must also have
* constructors which either implicitly or explicitly delegate to {@code super();}.
*
* <p>This class explicitly registers the following {@code TestExecutionListener}
* implementations. If you want to switch to using the <em>default</em> set of
* listeners, see the class-level Javadoc for
* {@link TestExecutionListeners @TestExecutionListeners} for details.
* <p>The following {@link org.springframework.test.context.TestExecutionListener
* TestExecutionListeners} are configured by default:
*
* <ul>
* <li>{@link org.springframework.test.context.web.ServletTestExecutionListener}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -56,10 +56,8 @@ import org.springframework.util.Assert;
* <p>Concrete subclasses must fulfill the same requirements outlined in
* {@link AbstractTestNGSpringContextTests}.
*
* <p>This class explicitly registers the following {@code TestExecutionListener}
* implementations. If you want to switch to using the <em>default</em> set of
* listeners, see the class-level Javadoc for
* {@link TestExecutionListeners @TestExecutionListeners} for details.
* <p>The following {@link org.springframework.test.context.TestExecutionListener
* TestExecutionListeners} are configured by default:
*
* <ul>
* <li>{@link org.springframework.test.context.web.ServletTestExecutionListener}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -43,7 +43,6 @@ public abstract class AopTestUtils {
* {@linkplain AopUtils#isAopProxy proxy}, the target of the proxy will
* be returned; otherwise, the {@code candidate} will be returned
* <em>as is</em>.
* @param <T> the type of the target object
* @param candidate the instance to check (potentially a Spring AOP proxy;
* never {@code null})
* @return the target object or the {@code candidate} (never {@code null})
@@ -76,18 +75,11 @@ public abstract class AopTestUtils {
* {@linkplain AopUtils#isAopProxy proxy}, the ultimate target of all
* nested proxies will be returned; otherwise, the {@code candidate}
* will be returned <em>as is</em>.
* <p>NOTE: If the top-level proxy or a nested proxy is not backed by a
* {@linkplain org.springframework.aop.TargetSource#isStatic() static}
* {@link org.springframework.aop.TargetSource TargetSource}, invocation of
* this utility method may result in undesired behavior such as infinite
* recursion leading to a {@link StackOverflowError}.
* @param <T> the type of the target object
* @param candidate the instance to check (potentially a Spring AOP proxy;
* never {@code null})
* @return the target object or the {@code candidate} (never {@code null})
* @throws IllegalStateException if an error occurs while unwrapping a proxy
* @see Advised#getTargetSource()
* @see org.springframework.aop.TargetSource#isStatic()
* @see org.springframework.aop.framework.AopProxyUtils#ultimateTargetClass
*/
@SuppressWarnings("unchecked")
@@ -1,139 +0,0 @@
/*
* Copyright 2002-2022 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.test.util;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.util.Random;
import javax.net.ServerSocketFactory;
import org.springframework.util.Assert;
/**
* Simple utility for finding available TCP ports on {@code localhost} for use in
* integration testing scenarios.
*
* <p>This is a limited form of {@link org.springframework.util.SocketUtils} which
* has been deprecated since Spring Framework 5.3.16 and removed in Spring
* Framework 6.0.
*
* <p>{@code TestSocketUtils} can be used in integration tests which start an
* external server on an available random port. However, these utilities make no
* guarantee about the subsequent availability of a given port and are therefore
* unreliable. Instead of using {@code TestSocketUtils} to find an available local
* port for a server, it is recommended that you rely on a server's ability to
* start on a random <em>ephemeral</em> port that it selects or is assigned by the
* operating system. To interact with that server, you should query the server
* for the port it is currently using.
*
* @author Sam Brannen
* @author Ben Hale
* @author Arjen Poutsma
* @author Gunnar Hillert
* @author Gary Russell
* @author Chris Bono
* @since 5.3.24
*/
public class TestSocketUtils {
/**
* The minimum value for port ranges used when finding an available TCP port.
*/
static final int PORT_RANGE_MIN = 1024;
/**
* The maximum value for port ranges used when finding an available TCP port.
*/
static final int PORT_RANGE_MAX = 65535;
private static final int PORT_RANGE_PLUS_ONE = PORT_RANGE_MAX - PORT_RANGE_MIN + 1;
private static final int MAX_ATTEMPTS = 1_000;
private static final Random random = new Random(System.nanoTime());
private static final TestSocketUtils INSTANCE = new TestSocketUtils();
/**
* Although {@code TestSocketUtils} consists solely of static utility methods,
* this constructor is intentionally {@code public}.
* <h5>Rationale</h5>
* <p>Static methods from this class may be invoked from within XML
* configuration files using the Spring Expression Language (SpEL) and the
* following syntax.
* <pre><code>
* &lt;bean id="myBean" ... p:port="#{T(org.springframework.test.util.TestSocketUtils).findAvailableTcpPort()}" /&gt;</code>
* </pre>
* <p>If this constructor were {@code private}, you would be required to supply
* the fully qualified class name to SpEL's {@code T()} function for each usage.
* Thus, the fact that this constructor is {@code public} allows you to reduce
* boilerplate configuration with SpEL as can be seen in the following example.
* <pre><code>
* &lt;bean id="socketUtils" class="org.springframework.test.util.TestSocketUtils" /&gt;
* &lt;bean id="myBean" ... p:port="#{socketUtils.findAvailableTcpPort()}" /&gt;</code>
* </pre>
*/
public TestSocketUtils() {
}
/**
* Find an available TCP port randomly selected from the range [1024, 65535].
* @return an available TCP port number
* @throws IllegalStateException if no available port could be found
*/
public static int findAvailableTcpPort() {
return INSTANCE.findAvailableTcpPortInternal();
}
/**
* Internal implementation of {@link #findAvailableTcpPort()}.
* <p>Package-private solely for testing purposes.
*/
int findAvailableTcpPortInternal() {
int candidatePort;
int searchCounter = 0;
do {
Assert.state(++searchCounter <= MAX_ATTEMPTS, () -> String.format(
"Could not find an available TCP port in the range [%d, %d] after %d attempts",
PORT_RANGE_MIN, PORT_RANGE_MAX, MAX_ATTEMPTS));
candidatePort = PORT_RANGE_MIN + random.nextInt(PORT_RANGE_PLUS_ONE);
}
while (!isPortAvailable(candidatePort));
return candidatePort;
}
/**
* Determine if the specified TCP port is currently available on {@code localhost}.
* <p>Package-private solely for testing purposes.
*/
boolean isPortAvailable(int port) {
try {
ServerSocket serverSocket = ServerSocketFactory.getDefault()
.createServerSocket(port, 1, InetAddress.getByName("localhost"));
serverSocket.close();
return true;
}
catch (Exception ex) {
return false;
}
}
}
@@ -230,7 +230,7 @@ class DefaultWebTestClientBuilder implements WebTestClient.Builder {
@Override
public WebTestClient.Builder entityExchangeResultConsumer(Consumer<EntityExchangeResult<?>> entityResultConsumer) {
Assert.notNull(entityResultConsumer, "'entityResultConsumer' is required");
Assert.notNull(entityResultConsumer, "`entityResultConsumer` is required");
this.entityResultConsumer = this.entityResultConsumer.andThen(entityResultConsumer);
return this;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -50,7 +50,6 @@ import org.springframework.util.MultiValueMap;
* respectively.
*
* @author Rossen Stoyanchev
* @author Sam Brannen
* @since 5.0
* @see EntityExchangeResult
* @see FluxExchangeResult
@@ -172,8 +171,6 @@ public class ExchangeResult {
/**
* Return the HTTP status code as an {@link HttpStatus} enum value.
* @throws IllegalArgumentException in case of an unknown HTTP status code
* @see #getRawStatusCode()
*/
public HttpStatus getStatus() {
return this.response.getStatusCode();
@@ -251,22 +248,13 @@ public class ExchangeResult {
"\n" +
formatBody(getRequestHeaders().getContentType(), this.requestBody) + "\n" +
"\n" +
"< " + formatStatus() + "\n" +
"< " + getStatus() + " " + getStatus().getReasonPhrase() + "\n" +
"< " + formatHeaders(getResponseHeaders(), "\n< ") + "\n" +
"\n" +
formatBody(getResponseHeaders().getContentType(), this.responseBody) +"\n" +
formatMockServerResult();
}
private String formatStatus() {
try {
return getStatus() + " " + getStatus().getReasonPhrase();
}
catch (Exception ex) {
return Integer.toString(getRawStatusCode());
}
}
private String formatHeaders(HttpHeaders headers, String delimiter) {
return headers.entrySet().stream()
.map(entry -> entry.getKey() + ": " + entry.getValue())
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -148,8 +148,8 @@ public class MockHttpServletRequestBuilder
private static URI initUri(String url, Object[] vars) {
Assert.notNull(url, "'url' must not be null");
Assert.isTrue(url.startsWith("/") || url.startsWith("http://") || url.startsWith("https://"),
() -> "'url' should start with a path or be a complete HTTP URL: " + url);
Assert.isTrue(url.startsWith("/") || url.startsWith("http://") || url.startsWith("https://"), "" +
"'url' should start with a path or be a complete HTTP URL: " + url);
return UriComponentsBuilder.fromUriString(url).buildAndExpand(vars).encode().toUri();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -42,8 +42,8 @@ public class HybridContextLoader extends AbstractGenericContextLoader {
@Override
protected void validateMergedContextConfiguration(MergedContextConfiguration mergedConfig) {
Assert.isTrue(mergedConfig.hasResources(),
() -> getClass().getSimpleName() + " requires either classes or locations");
Assert.isTrue(mergedConfig.hasClasses() || mergedConfig.hasLocations(), getClass().getSimpleName()
+ " requires either classes or locations");
}
@Override
@@ -1,61 +0,0 @@
/*
* Copyright 2002-2022 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.test.util;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Unit tests for {@link TestSocketUtils}.
*
* @author Sam Brannen
* @author Gary Russell
* @since 5.3.24
*/
class TestSocketUtilsTests {
@Test
void canBeInstantiated() {
// Just making sure somebody doesn't try to make SocketUtils abstract,
// since that would be a breaking change due to the intentional public
// constructor.
new TestSocketUtils();
}
@RepeatedTest(10)
void findAvailableTcpPort() {
assertThat(TestSocketUtils.findAvailableTcpPort())
.isBetween(TestSocketUtils.PORT_RANGE_MIN, TestSocketUtils.PORT_RANGE_MAX);
}
@Test
void findAvailableTcpPortWhenNoAvailablePortFoundInMaxAttempts() {
TestSocketUtils socketUtils = new TestSocketUtils() {
@Override
boolean isPortAvailable(int port) {
return false;
}
};
assertThatIllegalStateException()
.isThrownBy(socketUtils::findAvailableTcpPortInternal)
.withMessage("Could not find an available TCP port in the range [1024, 65535] after 1000 attempts");
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.mockito.Mockito.mock;
* Unit tests for {@link StatusAssertions}.
*
* @author Rossen Stoyanchev
* @author Sam Brannen
*/
class StatusAssertionTests {
@@ -57,20 +56,9 @@ class StatusAssertionTests {
assertions.isEqualTo(408));
}
@Test // gh-23630, gh-29283
@Test // gh-23630
void isEqualToWithCustomStatus() {
StatusAssertions assertions = statusAssertions(600);
// Success
assertions.isEqualTo(600);
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.isEqualTo(HttpStatus.REQUEST_TIMEOUT));
// Wrong status value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.isEqualTo(408));
statusAssertions(600).isEqualTo(600);
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -15,7 +15,7 @@
*/
package org.springframework.test.context
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
@@ -36,8 +36,8 @@ class KotlinDynamicPropertySourceIntegrationTests {
@Test
fun hasInjectedValues(@Autowired service: Service) {
assertThat(service.ip).isEqualTo("127.0.0.1")
assertThat(service.port).isEqualTo(4242)
Assertions.assertThat(service.ip).isEqualTo("127.0.0.1")
Assertions.assertThat(service.port).isEqualTo(4242)
}
@Configuration
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -57,7 +57,7 @@ final class TransactionalOperatorImpl implements TransactionalOperator {
*/
TransactionalOperatorImpl(ReactiveTransactionManager transactionManager, TransactionDefinition transactionDefinition) {
Assert.notNull(transactionManager, "ReactiveTransactionManager must not be null");
Assert.notNull(transactionDefinition, "TransactionDefinition must not be null");
Assert.notNull(transactionManager, "TransactionDefinition must not be null");
this.transactionManager = transactionManager;
this.transactionDefinition = transactionDefinition;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -21,8 +21,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.fail
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
import org.springframework.aop.framework.ProxyFactory
import org.springframework.transaction.interceptor.TransactionInterceptor
@@ -61,6 +60,7 @@ class CoroutinesAnnotationTransactionInterceptorTests {
}
catch (ex: IllegalStateException) {
}
}
assertReactiveGetTransactionAndRollbackCount(1)
}
@@ -72,7 +72,7 @@ class CoroutinesAnnotationTransactionInterceptorTests {
proxyFactory.addAdvice(TransactionInterceptor(rtm, source))
val proxy = proxyFactory.proxy as TestWithCoroutines
runBlocking {
assertThat(proxy.suspendingValueSuccess()).isEqualTo("foo")
Assertions.assertThat(proxy.suspendingValueSuccess()).isEqualTo("foo")
}
assertReactiveGetTransactionAndCommitCount(1)
}
@@ -86,7 +86,7 @@ class CoroutinesAnnotationTransactionInterceptorTests {
runBlocking {
try {
proxy.suspendingValueFailure()
fail("No exception thrown as expected")
Assertions.fail("No exception thrown as expected")
}
catch (ex: IllegalStateException) {
}
@@ -101,7 +101,7 @@ class CoroutinesAnnotationTransactionInterceptorTests {
proxyFactory.addAdvice(TransactionInterceptor(rtm, source))
val proxy = proxyFactory.proxy as TestWithCoroutines
runBlocking {
assertThat(proxy.suspendingFlowSuccess().toList()).containsExactly("foo", "foo")
Assertions.assertThat(proxy.suspendingFlowSuccess().toList()).containsExactly("foo", "foo")
}
assertReactiveGetTransactionAndCommitCount(1)
}
@@ -113,19 +113,19 @@ class CoroutinesAnnotationTransactionInterceptorTests {
proxyFactory.addAdvice(TransactionInterceptor(rtm, source))
val proxy = proxyFactory.proxy as TestWithCoroutines
runBlocking {
assertThat(proxy.flowSuccess().toList()).containsExactly("foo", "foo")
Assertions.assertThat(proxy.flowSuccess().toList()).containsExactly("foo", "foo")
}
assertReactiveGetTransactionAndCommitCount(1)
}
private fun assertReactiveGetTransactionAndCommitCount(expectedCount: Int) {
assertThat(rtm.begun).isEqualTo(expectedCount)
assertThat(rtm.commits).isEqualTo(expectedCount)
Assertions.assertThat(rtm.begun).isEqualTo(expectedCount)
Assertions.assertThat(rtm.commits).isEqualTo(expectedCount)
}
private fun assertReactiveGetTransactionAndRollbackCount(expectedCount: Int) {
assertThat(rtm.begun).isEqualTo(expectedCount)
assertThat(rtm.rollbacks).isEqualTo(expectedCount)
Assertions.assertThat(rtm.begun).isEqualTo(expectedCount)
Assertions.assertThat(rtm.rollbacks).isEqualTo(expectedCount)
}
@Transactional
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@ package org.springframework.transaction.interceptor
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions
import org.assertj.core.api.Fail
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@@ -188,7 +188,7 @@ abstract class AbstractCoroutinesTransactionAspectTests {
ex: Exception, shouldRollback: Boolean, rollbackException: Boolean) {
val txatt: TransactionAttribute = object : DefaultTransactionAttribute() {
override fun rollbackOn(t: Throwable): Boolean {
assertThat(t).isSameAs(ex)
Assertions.assertThat(t).isSameAs(ex)
return shouldRollback
}
}
@@ -218,9 +218,9 @@ abstract class AbstractCoroutinesTransactionAspectTests {
}
catch (actual: Exception) {
if (rollbackException) {
assertThat(actual).hasMessage(tex.message).isInstanceOf(tex::class.java)
Assertions.assertThat(actual).hasMessage(tex.message).isInstanceOf(tex::class.java)
} else {
assertThat(actual).hasMessage(ex.message).isInstanceOf(ex::class.java)
Assertions.assertThat(actual).hasMessage(ex.message).isInstanceOf(ex::class.java)
}
}
}
@@ -259,7 +259,7 @@ abstract class AbstractCoroutinesTransactionAspectTests {
itb.getName()
}
catch (actual: Exception) {
assertThat(actual).isInstanceOf(CannotCreateTransactionException::class.java)
Assertions.assertThat(actual).isInstanceOf(CannotCreateTransactionException::class.java)
}
}
}
@@ -291,11 +291,11 @@ abstract class AbstractCoroutinesTransactionAspectTests {
itb.setName(name)
}
catch (ex: Exception) {
assertThat(ex).isInstanceOf(RuntimeException::class.java)
assertThat(ex.cause).hasMessage(ex.message).isInstanceOf(ex::class.java)
Assertions.assertThat(ex).isInstanceOf(RuntimeException::class.java)
Assertions.assertThat(ex.cause).hasMessage(ex.message).isInstanceOf(ex::class.java)
}
// Should have invoked target and changed name
assertThat(itb.getName()).isEqualTo(name)
Assertions.assertThat(itb.getName()).isEqualTo(name)
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -16,7 +16,7 @@
package org.springframework.transaction.interceptor
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions
import org.springframework.aop.framework.ProxyFactory
import org.springframework.transaction.ReactiveTransactionManager
@@ -44,9 +44,9 @@ class CoroutinesTransactionInterceptorTests : AbstractCoroutinesTransactionAspec
override fun advised(target: Any, rtm: ReactiveTransactionManager, tas: TransactionAttributeSource): Any {
val ti = TransactionInterceptor()
ti.transactionManager = rtm
assertThat(ti.transactionManager).isEqualTo(rtm)
Assertions.assertThat(ti.transactionManager).isEqualTo(rtm)
ti.transactionAttributeSource = tas
assertThat(ti.transactionAttributeSource).isEqualTo(tas)
Assertions.assertThat(ti.transactionAttributeSource).isEqualTo(tas)
val pf = ProxyFactory(target)
pf.addAdvice(0, ti)
return pf.proxy
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -465,9 +465,8 @@ public final class ContentDisposition {
* @see <a href="https://tools.ietf.org/html/rfc5987">RFC 5987</a>
*/
private static String decodeFilename(String filename, Charset charset) {
Assert.notNull(filename, "'filename' must not be null");
Assert.notNull(charset, "'charset' must not be null");
Assert.notNull(filename, "'input' String` should not be null");
Assert.notNull(charset, "'charset' should not be null");
byte[] value = filename.getBytes(charset);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int index = 0;
@@ -532,10 +531,10 @@ public final class ContentDisposition {
* @see <a href="https://tools.ietf.org/html/rfc5987">RFC 5987</a>
*/
private static String encodeFilename(String input, Charset charset) {
Assert.notNull(input, "'input' is required");
Assert.notNull(charset, "'charset' is required");
Assert.notNull(input, "`input` is required");
Assert.notNull(charset, "`charset` is required");
Assert.isTrue(!StandardCharsets.US_ASCII.equals(charset), "ASCII does not require encoding");
Assert.isTrue(UTF_8.equals(charset) || ISO_8859_1.equals(charset), "Only UTF-8 and ISO-8859-1 are supported");
Assert.isTrue(UTF_8.equals(charset) || ISO_8859_1.equals(charset), "Only UTF-8 and ISO-8859-1 supported.");
byte[] source = input.getBytes(charset);
int len = source.length;
StringBuilder sb = new StringBuilder(len << 1);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -65,7 +65,7 @@ public abstract class HttpRange {
long contentLength = getLengthFor(resource);
long start = getRangeStart(contentLength);
long end = getRangeEnd(contentLength);
Assert.isTrue(start < contentLength, () -> "'position' exceeds the resource length " + contentLength);
Assert.isTrue(start < contentLength, "'position' exceeds the resource length " + contentLength);
return new ResourceRegion(resource, start, end - start + 1);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -531,10 +531,10 @@ public class MediaType extends MimeType implements Serializable {
protected void checkParameters(String parameter, String value) {
super.checkParameters(parameter, value);
if (PARAM_QUALITY_FACTOR.equals(parameter)) {
String unquotedValue = unquote(value);
double d = Double.parseDouble(unquotedValue);
value = unquote(value);
double d = Double.parseDouble(value);
Assert.isTrue(d >= 0D && d <= 1D,
() -> "Invalid quality value \"" + unquotedValue + "\": should be between 0.0 and 1.0");
"Invalid quality value \"" + value + "\": should be between 0.0 and 1.0");
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -54,10 +54,6 @@ public abstract class InterceptingHttpAccessor extends HttpAccessor {
* Set the request interceptors that this accessor should use.
* <p>The interceptors will get immediately sorted according to their
* {@linkplain AnnotationAwareOrderComparator#sort(List) order}.
* <p><strong>Note:</strong> This method does not support concurrent changes,
* and in most cases should not be called after initialization on startup.
* See also related note on {@link org.springframework.web.client.RestTemplate}
* regarding concurrent configuration changes.
* @see #getRequestFactory()
* @see AnnotationAwareOrderComparator
*/
@@ -231,7 +231,7 @@ public abstract class Jackson2CodecSupport {
JsonView annotation = getAnnotation(param, JsonView.class);
if (annotation != null) {
Class<?>[] classes = annotation.value();
Assert.isTrue(classes.length == 1, () -> JSON_VIEW_HINT_ERROR + param);
Assert.isTrue(classes.length == 1, JSON_VIEW_HINT_ERROR + param);
hints = (hints != null ? hints : new HashMap<>(1));
hints.put(JSON_VIEW_HINT, classes[0]);
}
@@ -229,7 +229,6 @@ final class PartGenerator extends BaseSubscriber<MultipartParser.Token> {
if (upstream() != null &&
!this.sink.isCancelled() &&
this.sink.requestedFromDownstream() > 0 &&
this.state.get().canRequest() &&
this.requestOutstanding.compareAndSet(false, true)) {
request(1);
}
@@ -292,13 +291,6 @@ final class PartGenerator extends BaseSubscriber<MultipartParser.Token> {
default void error(Throwable throwable) {
}
/**
* Indicates whether the current state is ready to accept a new token.
*/
default boolean canRequest() {
return true;
}
/**
* Cleans up any state.
*/
@@ -822,11 +814,6 @@ final class PartGenerator extends BaseSubscriber<MultipartParser.Token> {
}
}
@Override
public boolean canRequest() {
return false;
}
@Override
public void dispose() {
this.disposed = true;
@@ -128,7 +128,7 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
*/
public void setCacheDir(File cacheDir) {
Assert.notNull(cacheDir, "'cacheDir' must not be null");
Assert.isTrue(cacheDir.isDirectory(), () -> "'cacheDir' is not a directory: " + cacheDir);
Assert.isTrue(cacheDir.isDirectory(), "'cacheDir' is not a directory");
this.cacheDir = cacheDir;
}
@@ -436,7 +436,7 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
StringBuilder builder = new StringBuilder();
formData.forEach((name, values) -> {
if (name == null) {
Assert.isTrue(CollectionUtils.isEmpty(values), () -> "Null name in form data: " + formData);
Assert.isTrue(CollectionUtils.isEmpty(values), "Null name in form data: " + formData);
return;
}
values.forEach(value -> {
@@ -356,7 +356,7 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
Charset charset = getCharset(contentType);
ObjectMapper objectMapper = selectObjectMapper(javaType.getRawClass(), contentType);
Assert.state(objectMapper != null, () -> "No ObjectMapper for " + javaType);
Assert.state(objectMapper != null, "No ObjectMapper for " + javaType);
boolean isUnicode = ENCODINGS.containsKey(charset.name()) ||
"UTF-16".equals(charset.name()) ||
@@ -419,7 +419,7 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
Class<?> clazz = (object instanceof MappingJacksonValue ?
((MappingJacksonValue) object).getValue().getClass() : object.getClass());
ObjectMapper objectMapper = selectObjectMapper(clazz, contentType);
Assert.state(objectMapper != null, () -> "No ObjectMapper for " + clazz.getName());
Assert.state(objectMapper != null, "No ObjectMapper for " + clazz.getName());
OutputStream outputStream = StreamUtils.nonClosing(outputMessage.getBody());
try (JsonGenerator generator = objectMapper.getFactory().createGenerator(outputStream, encoding)) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -93,7 +93,7 @@ class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder {
@Override
public ServerHttpRequest.Builder path(String path) {
Assert.isTrue(path.startsWith("/"), () -> "The path does not have a leading slash: " + path);
Assert.isTrue(path.startsWith("/"), "The path does not have a leading slash.");
this.uriPath = path;
return this;
}
@@ -90,7 +90,7 @@ class ServletServerHttpRequest extends AbstractServerHttpRequest {
super(initUri(request), request.getContextPath() + servletPath, initHeaders(headers, request));
Assert.notNull(bufferFactory, "'bufferFactory' must not be null");
Assert.isTrue(bufferSize > 0, "'bufferSize' must be greater than 0");
Assert.isTrue(bufferSize > 0, "'bufferSize' must be higher than 0");
this.request = request;
this.bufferFactory = bufferFactory;
@@ -63,12 +63,12 @@ class UndertowServerHttpResponse extends AbstractListenerServerHttpResponse impl
HttpServerExchange exchange, DataBufferFactory bufferFactory, UndertowServerHttpRequest request) {
super(bufferFactory, createHeaders(exchange));
Assert.notNull(exchange, "HttpServerExchange must not be null");
this.exchange = exchange;
this.request = request;
}
private static HttpHeaders createHeaders(HttpServerExchange exchange) {
Assert.notNull(exchange, "HttpServerExchange must not be null");
UndertowHeadersAdapter headersMap = new UndertowHeadersAdapter(exchange.getResponseHeaders());
return new HttpHeaders(headersMap);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -68,17 +68,11 @@ import org.springframework.web.util.UriTemplateHandler;
/**
* Synchronous client to perform HTTP requests, exposing a simple, template
* method API over underlying HTTP client libraries such as the JDK
* {@code HttpURLConnection}, Apache HttpComponents, and others. RestTemplate
* offers templates for common scenarios by HTTP method, in addition to the
* generalized {@code exchange} and {@code execute} methods that support of
* less frequent cases.
* {@code HttpURLConnection}, Apache HttpComponents, and others.
*
* <p>RestTemplate is typically used as a shared component. However, its
* configuration does not support concurrent modification, and as such its
* configuration is typically prepared on startup. If necessary, you can create
* multiple, differently configured RestTemplate instances on startup. Such
* instances may use the same the underlying {@link ClientHttpRequestFactory}
* if they need to share HTTP client resources.
* <p>The RestTemplate offers templates for common scenarios by HTTP method, in
* addition to the generalized {@code exchange} and {@code execute} methods that
* support of less frequent cases.
*
* <p><strong>NOTE:</strong> As of 5.0 this class is in maintenance mode, with
* only minor requests for changes and bugs to be accepted going forward. Please,
@@ -220,12 +220,6 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
if (this.notModified && response != null) {
response.setStatus(HttpStatus.PRECONDITION_FAILED.value());
}
if (SAFE_METHODS.contains(getRequest().getMethod())) {
if (StringUtils.hasLength(etag) && response.getHeader(HttpHeaders.ETAG) == null) {
response.setHeader(HttpHeaders.ETAG, padEtagIfNecessary(etag));
}
response.setDateHeader(HttpHeaders.LAST_MODIFIED, lastModifiedTimestamp);
}
return this.notModified;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -196,7 +196,7 @@ public final class WebAsyncManager {
*/
public void registerCallableInterceptor(Object key, CallableProcessingInterceptor interceptor) {
Assert.notNull(key, "Key is required");
Assert.notNull(interceptor, "CallableProcessingInterceptor is required");
Assert.notNull(interceptor, "CallableProcessingInterceptor is required");
this.callableInterceptors.put(key, interceptor);
}

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