Compare commits

..

1 Commits

Author SHA1 Message Date
Spring Builds b02f4a06ca Release v5.3.28 2023-06-15 07:19:13 +00:00
218 changed files with 2065 additions and 3257 deletions
+6 -6
View File
@@ -28,8 +28,8 @@ configure(allprojects) { project ->
dependencyManagement {
imports {
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.7"
mavenBom "io.netty:netty-bom:4.1.95.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.34"
mavenBom "io.netty:netty-bom:4.1.93.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.33"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR13"
mavenBom "io.rsocket:rsocket-bom:1.1.3"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.51.v20230217"
@@ -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.78') {
dependencySet(group: 'org.apache.tomcat', version: '9.0.75') {
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.78') {
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.75') {
entry 'tomcat-embed-core'
entry 'tomcat-embed-websocket'
}
dependencySet(group: 'io.undertow', version: '2.2.25.Final') {
dependencySet(group: 'io.undertow', version: '2.2.24.Final') {
entry 'undertow-core'
entry('undertow-servlet') {
exclude group: "org.jboss.spec.javax.servlet", name: "jboss-servlet-api_4.0_spec"
@@ -340,7 +340,7 @@ configure([rootProject] + javaProjects) { project ->
}
checkstyle {
toolVersion = "10.12.1"
toolVersion = "10.9.3"
configDirectory.set(rootProject.file("src/checkstyle"))
}
+1 -1
View File
@@ -1,4 +1,4 @@
FROM ubuntu:jammy-20230624
FROM ubuntu:focal-20220922
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
-2
View File
@@ -5,8 +5,6 @@ image_resource:
source:
repository: springio/github-changelog-generator
tag: '0.0.7'
username: ((docker-hub-username))
password: ((docker-hub-password))
inputs:
- name: git-repo
- name: artifactory-repo
-2
View File
@@ -5,8 +5,6 @@ image_resource:
source:
repository: springio/concourse-release-scripts
tag: '0.3.4'
username: ((docker-hub-username))
password: ((docker-hub-password))
inputs:
- name: git-repo
- name: artifactory-repo
+1 -1
View File
@@ -1,4 +1,4 @@
version=5.3.30
version=5.3.28
org.gradle.jvmargs=-Xmx2048m
org.gradle.caching=true
org.gradle.parallel=true
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -60,8 +60,8 @@ class ScheduledAndTransactionalAnnotationIntegrationTests {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(Config.class, JdkProxyTxConfig.class, RepoConfigA.class);
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(ctx::refresh)
.withCauseInstanceOf(IllegalStateException.class);
.isThrownBy(ctx::refresh)
.withCauseInstanceOf(IllegalStateException.class);
}
@Test
@@ -70,7 +70,7 @@ class ScheduledAndTransactionalAnnotationIntegrationTests {
ctx.register(Config.class, SubclassProxyTxConfig.class, RepoConfigA.class);
ctx.refresh();
Thread.sleep(200); // allow @Scheduled method to be called several times
Thread.sleep(100); // allow @Scheduled method to be called several times
MyRepository repository = ctx.getBean(MyRepository.class);
CallCountingTransactionManager txManager = ctx.getBean(CallCountingTransactionManager.class);
@@ -85,7 +85,7 @@ class ScheduledAndTransactionalAnnotationIntegrationTests {
ctx.register(Config.class, JdkProxyTxConfig.class, RepoConfigB.class);
ctx.refresh();
Thread.sleep(200); // allow @Scheduled method to be called several times
Thread.sleep(100); // allow @Scheduled method to be called several times
MyRepositoryWithScheduledMethod repository = ctx.getBean(MyRepositoryWithScheduledMethod.class);
CallCountingTransactionManager txManager = ctx.getBean(CallCountingTransactionManager.class);
@@ -100,7 +100,7 @@ class ScheduledAndTransactionalAnnotationIntegrationTests {
ctx.register(AspectConfig.class, MyRepositoryWithScheduledMethodImpl.class);
ctx.refresh();
Thread.sleep(200); // allow @Scheduled method to be called several times
Thread.sleep(100); // allow @Scheduled method to be called several times
MyRepositoryWithScheduledMethod repository = ctx.getBean(MyRepositoryWithScheduledMethod.class);
assertThat(AopUtils.isCglibProxy(repository)).isTrue();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -248,8 +248,8 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
/**
* If a pointcut expression has been specified in XML, the user cannot
* write "and" as "&&" (though {@code &&} will work).
* <p>We also allow "and" between two pointcut sub-expressions.
* write {@code and} as "&&" (though &amp;&amp; will work).
* We also allow {@code and} between two pointcut sub-expressions.
* <p>This method converts back to {@code &&} for the AspectJ pointcut parser.
*/
private String replaceBooleanOperators(String pcExpr) {
@@ -527,7 +527,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
return false;
}
AspectJExpressionPointcut otherPc = (AspectJExpressionPointcut) other;
return ObjectUtils.nullSafeEquals(getExpression(), otherPc.getExpression()) &&
return ObjectUtils.nullSafeEquals(this.getExpression(), otherPc.getExpression()) &&
ObjectUtils.nullSafeEquals(this.pointcutDeclarationScope, otherPc.pointcutDeclarationScope) &&
ObjectUtils.nullSafeEquals(this.pointcutParameterNames, otherPc.pointcutParameterNames) &&
ObjectUtils.nullSafeEquals(this.pointcutParameterTypes, otherPc.pointcutParameterTypes);
@@ -535,7 +535,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
@Override
public int hashCode() {
int hashCode = ObjectUtils.nullSafeHashCode(getExpression());
int hashCode = ObjectUtils.nullSafeHashCode(this.getExpression());
hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutDeclarationScope);
hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutParameterNames);
hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutParameterTypes);
@@ -424,9 +424,10 @@ class CglibAopProxy implements AopProxy, Serializable {
/**
* Method interceptor used for static targets with no advice chain. The call is
* passed directly back to the target. Used when the proxy needs to be exposed
* and it can't be determined that the method won't return {@code this}.
* Method interceptor used for static targets with no advice chain. The call
* is passed directly back to the target. Used when the proxy needs to be
* exposed and it can't be determined that the method won't return
* {@code this}.
*/
private static class StaticUnadvisedInterceptor implements MethodInterceptor, Serializable {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -77,7 +77,9 @@ public class ThrowsAdviceInterceptorTests {
given(mi.getMethod()).willReturn(Object.class.getMethod("hashCode"));
given(mi.getThis()).willReturn(new Object());
given(mi.proceed()).willThrow(ex);
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() -> ti.invoke(mi)).isSameAs(ex);
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() ->
ti.invoke(mi))
.isSameAs(ex);
assertThat(th.getCalls()).isEqualTo(1);
assertThat(th.getCalls("ioException")).isEqualTo(1);
}
@@ -90,7 +92,9 @@ public class ThrowsAdviceInterceptorTests {
ConnectException ex = new ConnectException("");
MethodInvocation mi = mock(MethodInvocation.class);
given(mi.proceed()).willThrow(ex);
assertThatExceptionOfType(ConnectException.class).isThrownBy(() -> ti.invoke(mi)).isSameAs(ex);
assertThatExceptionOfType(ConnectException.class).isThrownBy(() ->
ti.invoke(mi))
.isSameAs(ex);
assertThat(th.getCalls()).isEqualTo(1);
assertThat(th.getCalls("remoteException")).isEqualTo(1);
}
@@ -113,7 +117,9 @@ public class ThrowsAdviceInterceptorTests {
ConnectException ex = new ConnectException("");
MethodInvocation mi = mock(MethodInvocation.class);
given(mi.proceed()).willThrow(ex);
assertThatExceptionOfType(Throwable.class).isThrownBy(() -> ti.invoke(mi)).isSameAs(t);
assertThatExceptionOfType(Throwable.class).isThrownBy(() ->
ti.invoke(mi))
.isSameAs(t);
assertThat(th.getCalls()).isEqualTo(1);
assertThat(th.getCalls("remoteException")).isEqualTo(1);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -248,22 +248,9 @@ public final class CachedIntrospectionResults {
return beanInfo;
}
}
BeanInfo beanInfo = (shouldIntrospectorIgnoreBeaninfoClasses ?
return (shouldIntrospectorIgnoreBeaninfoClasses ?
Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO) :
Introspector.getBeanInfo(beanClass));
// Immediately remove class from Introspector cache to allow for proper garbage
// collection on class loader shutdown; we cache it in CachedIntrospectionResults
// in a GC-friendly manner. This is necessary (again) for the JDK ClassInfo cache.
Class<?> classToFlush = beanClass;
do {
Introspector.flushFromCaches(classToFlush);
classToFlush = classToFlush.getSuperclass();
}
while (classToFlush != null && classToFlush != Object.class);
return beanInfo;
}
@@ -17,7 +17,6 @@
package org.springframework.beans.factory.annotation;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
@@ -63,10 +62,6 @@ import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -149,9 +144,6 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
@Nullable
private ConfigurableListableBeanFactory beanFactory;
@Nullable
private MetadataReaderFactory metadataReaderFactory;
private final Set<String> lookupMethodsChecked = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache = new ConcurrentHashMap<>(256);
@@ -246,7 +238,6 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
"AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory: " + beanFactory);
}
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
this.metadataReaderFactory = new SimpleMetadataReaderFactory(this.beanFactory.getBeanClassLoader());
}
@@ -472,11 +463,12 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
return InjectionMetadata.EMPTY;
}
final List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> fieldElements = new ArrayList<>();
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
@@ -487,11 +479,10 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
return;
}
boolean required = determineRequiredStatus(ann);
fieldElements.add(new AutowiredFieldElement(field, required));
currElements.add(new AutowiredFieldElement(field, required));
}
});
final List<InjectionMetadata.InjectedElement> methodElements = new ArrayList<>();
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
@@ -513,12 +504,11 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
methodElements.add(new AutowiredMethodElement(method, required, pd));
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, sortMethodElements(methodElements, targetClass));
elements.addAll(0, fieldElements);
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
@@ -583,47 +573,6 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
return BeanFactoryUtils.beansOfTypeIncludingAncestors(this.beanFactory, type);
}
/**
* Sort the method elements via ASM for deterministic declaration order if possible.
*/
private List<InjectionMetadata.InjectedElement> sortMethodElements(
List<InjectionMetadata.InjectedElement> methodElements, Class<?> targetClass) {
if (this.metadataReaderFactory != null && methodElements.size() > 1) {
// Try reading the class file via ASM for deterministic declaration order...
// Unfortunately, the JVM's standard reflection returns methods in arbitrary
// order, even between different runs of the same application on the same JVM.
try {
AnnotationMetadata asm =
this.metadataReaderFactory.getMetadataReader(targetClass.getName()).getAnnotationMetadata();
Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Autowired.class.getName());
if (asmMethods.size() >= methodElements.size()) {
List<InjectionMetadata.InjectedElement> candidateMethods = new ArrayList<>(methodElements);
List<InjectionMetadata.InjectedElement> selectedMethods = new ArrayList<>(asmMethods.size());
for (MethodMetadata asmMethod : asmMethods) {
for (Iterator<InjectionMetadata.InjectedElement> it = candidateMethods.iterator(); it.hasNext();) {
InjectionMetadata.InjectedElement element = it.next();
if (element.getMember().getName().equals(asmMethod.getMethodName())) {
selectedMethods.add(element);
it.remove();
break;
}
}
}
if (selectedMethods.size() == methodElements.size()) {
// All reflection-detected methods found in ASM method set -> proceed
return selectedMethods;
}
}
}
catch (IOException ex) {
logger.debug("Failed to read class file via ASM for determining @Autowired method order", ex);
// No worries, let's continue with the reflection metadata we started with...
}
}
return methodElements;
}
/**
* Register the specified bean as dependent on the autowired beans.
*/
@@ -645,7 +594,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
* Resolve the specified cached method argument or field value.
*/
@Nullable
private Object resolveCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {
private Object resolvedCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {
if (cachedArgument instanceof DependencyDescriptor) {
DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
Assert.state(this.beanFactory != null, "No BeanFactory available");
@@ -680,12 +629,10 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
Object value;
if (this.cached) {
try {
value = resolveCachedArgument(beanName, this.cachedFieldValue);
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (BeansException ex) {
// Unexpected target bean mismatch for cached argument -> re-resolve
this.cached = false;
logger.debug("Failed to resolve cached argument", ex);
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
value = resolveFieldValue(field, bean, beanName);
}
}
@@ -702,7 +649,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(2);
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
Object value;
@@ -714,23 +661,21 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
synchronized (this) {
if (!this.cached) {
Object cachedFieldValue = null;
if (value != null || this.required) {
Object cachedFieldValue = desc;
cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (value != null && autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
cachedFieldValue = new ShortcutDependencyDescriptor(desc, autowiredBeanName);
cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
this.cachedFieldValue = cachedFieldValue;
this.cached = true;
}
else {
this.cachedFieldValue = null;
// cached flag remains false
}
this.cachedFieldValue = cachedFieldValue;
this.cached = true;
}
}
return value;
@@ -764,12 +709,10 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
Object[] arguments;
if (this.cached) {
try {
arguments = resolveCachedArguments(beanName, this.cachedMethodArguments);
arguments = resolveCachedArguments(beanName);
}
catch (BeansException ex) {
// Unexpected target bean mismatch for cached argument -> re-resolve
this.cached = false;
logger.debug("Failed to resolve cached argument", ex);
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
arguments = resolveMethodArguments(method, bean, beanName);
}
}
@@ -788,13 +731,14 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
@Nullable
private Object[] resolveCachedArguments(@Nullable String beanName, @Nullable Object[] cachedMethodArguments) {
private Object[] resolveCachedArguments(@Nullable String beanName) {
Object[] cachedMethodArguments = this.cachedMethodArguments;
if (cachedMethodArguments == null) {
return null;
}
Object[] arguments = new Object[cachedMethodArguments.length];
for (int i = 0; i < arguments.length; i++) {
arguments[i] = resolveCachedArgument(beanName, cachedMethodArguments[i]);
arguments[i] = resolvedCachedArgument(beanName, cachedMethodArguments[i]);
}
return arguments;
}
@@ -804,7 +748,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
int argumentCount = method.getParameterCount();
Object[] arguments = new Object[argumentCount];
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
Set<String> autowiredBeanNames = new LinkedHashSet<>(argumentCount * 2);
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
for (int i = 0; i < arguments.length; i++) {
@@ -813,7 +757,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
currDesc.setContainingClass(bean.getClass());
descriptors[i] = currDesc;
try {
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeanNames, typeConverter);
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
if (arg == null && !this.required) {
arguments = null;
break;
@@ -827,27 +771,26 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
synchronized (this) {
if (!this.cached) {
if (arguments != null) {
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, argumentCount);
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == argumentCount) {
Iterator<String> it = autowiredBeanNames.iterator();
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
registerDependentBeans(beanName, autowiredBeans);
if (autowiredBeans.size() == argumentCount) {
Iterator<String> it = autowiredBeans.iterator();
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
String autowiredBeanName = it.next();
if (arguments[i] != null && beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
descriptors[i], autowiredBeanName);
descriptors[i], autowiredBeanName, paramTypes[i]);
}
}
}
this.cachedMethodArguments = cachedMethodArguments;
this.cached = true;
}
else {
this.cachedMethodArguments = null;
// cached flag remains false
}
this.cached = true;
}
}
return arguments;
@@ -863,14 +806,17 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
private final String shortcut;
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut) {
private final Class<?> requiredType;
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut, Class<?> requiredType) {
super(original);
this.shortcut = shortcut;
this.requiredType = requiredType;
}
@Override
public Object resolveShortcut(BeanFactory beanFactory) {
return beanFactory.getBean(this.shortcut, getDependencyType());
return beanFactory.getBean(this.shortcut, this.requiredType);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -1504,8 +1504,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
converter = bw;
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
Set<String> autowiredBeanNames = new LinkedHashSet<>(propertyNames.length * 2);
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -134,7 +134,7 @@ class BeanDefinitionValueResolver {
return resolveInnerBean(argName, innerBeanName, bd);
}
else if (value instanceof DependencyDescriptor) {
Set<String> autowiredBeanNames = new LinkedHashSet<>(2);
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
Object result = this.beanFactory.resolveDependency(
(DependencyDescriptor) value, this.beanName, autowiredBeanNames, this.typeConverter);
for (String autowiredBeanName : autowiredBeanNames) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -45,7 +45,6 @@ import org.springframework.beans.TypeConverter;
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.InjectionPoint;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
@@ -86,6 +85,12 @@ class ConstructorResolver {
private static final Object[] EMPTY_ARGS = new Object[0];
/**
* Marker for autowired arguments in a cached argument array, to be replaced
* by a {@linkplain #resolveAutowiredArgument resolved autowired argument}.
*/
private static final Object autowiredArgumentMarker = new Object();
private static final NamedThreadLocal<InjectionPoint> currentInjectionPoint =
new NamedThreadLocal<>("Current injection point");
@@ -724,7 +729,7 @@ class ConstructorResolver {
ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
Set<String> allAutowiredBeanNames = new LinkedHashSet<>(paramTypes.length * 2);
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
Class<?> paramType = paramTypes[paramIndex];
@@ -759,8 +764,8 @@ class ConstructorResolver {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
"Could not convert argument value of type [" +
ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
}
Object sourceHolder = valueHolder.getSource();
if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {
@@ -783,17 +788,11 @@ class ConstructorResolver {
"] - did you specify the correct bean references as arguments?");
}
try {
ConstructorDependencyDescriptor desc = new ConstructorDependencyDescriptor(methodParam, true);
Set<String> autowiredBeanNames = new LinkedHashSet<>(2);
Object arg = resolveAutowiredArgument(
desc, paramType, beanName, autowiredBeanNames, converter, fallback);
if (arg != null) {
setShortcutIfPossible(desc, paramType, autowiredBeanNames);
}
allAutowiredBeanNames.addAll(autowiredBeanNames);
args.rawArguments[paramIndex] = arg;
args.arguments[paramIndex] = arg;
args.preparedArguments[paramIndex] = desc;
Object autowiredArgument = resolveAutowiredArgument(
methodParam, beanName, autowiredBeanNames, converter, fallback);
args.rawArguments[paramIndex] = autowiredArgument;
args.arguments[paramIndex] = autowiredArgument;
args.preparedArguments[paramIndex] = autowiredArgumentMarker;
args.resolveNecessary = true;
}
catch (BeansException ex) {
@@ -803,7 +802,14 @@ class ConstructorResolver {
}
}
registerDependentBeans(executable, beanName, allAutowiredBeanNames);
for (String autowiredBeanName : autowiredBeanNames) {
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName +
"' via " + (executable instanceof Constructor ? "constructor" : "factory method") +
" to bean named '" + autowiredBeanName + "'");
}
}
return args;
}
@@ -823,61 +829,31 @@ class ConstructorResolver {
Object[] resolvedArgs = new Object[argsToResolve.length];
for (int argIndex = 0; argIndex < argsToResolve.length; argIndex++) {
Object argValue = argsToResolve[argIndex];
Class<?> paramType = paramTypes[argIndex];
boolean convertNecessary = false;
if (argValue instanceof ConstructorDependencyDescriptor) {
ConstructorDependencyDescriptor descriptor = (ConstructorDependencyDescriptor) argValue;
try {
argValue = resolveAutowiredArgument(descriptor, paramType, beanName,
null, converter, true);
}
catch (BeansException ex) {
// Unexpected target bean mismatch for cached argument -> re-resolve
Set<String> autowiredBeanNames = null;
if (descriptor.hasShortcut()) {
// Reset shortcut and try to re-resolve it in this thread...
descriptor.setShortcut(null);
autowiredBeanNames = new LinkedHashSet<>(2);
}
logger.debug("Failed to resolve cached argument", ex);
argValue = resolveAutowiredArgument(descriptor, paramType, beanName,
autowiredBeanNames, converter, true);
if (autowiredBeanNames != null && !descriptor.hasShortcut()) {
// We encountered as stale shortcut before, and the shortcut has
// not been re-resolved by another thread in the meantime...
if (argValue != null) {
setShortcutIfPossible(descriptor, paramType, autowiredBeanNames);
}
registerDependentBeans(executable, beanName, autowiredBeanNames);
}
}
MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex);
if (argValue == autowiredArgumentMarker) {
argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, true);
}
else if (argValue instanceof BeanMetadataElement) {
argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
convertNecessary = true;
}
else if (argValue instanceof String) {
argValue = this.beanFactory.evaluateBeanDefinitionString((String) argValue, mbd);
convertNecessary = true;
}
if (convertNecessary) {
MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex);
try {
argValue = converter.convertIfNecessary(argValue, paramType, methodParam);
}
catch (TypeMismatchException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
"Could not convert argument value of type [" + ObjectUtils.nullSafeClassName(argValue) +
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
}
Class<?> paramType = paramTypes[argIndex];
try {
resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam);
}
catch (TypeMismatchException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
"Could not convert argument value of type [" + ObjectUtils.nullSafeClassName(argValue) +
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
}
resolvedArgs[argIndex] = argValue;
}
return resolvedArgs;
}
private Constructor<?> getUserDeclaredConstructor(Constructor<?> constructor) {
protected Constructor<?> getUserDeclaredConstructor(Constructor<?> constructor) {
Class<?> declaringClass = constructor.getDeclaringClass();
Class<?> userClass = ClassUtils.getUserClass(declaringClass);
if (userClass != declaringClass) {
@@ -893,22 +869,23 @@ class ConstructorResolver {
}
/**
* Resolve the specified argument which is supposed to be autowired.
* Template method for resolving the specified argument which is supposed to be autowired.
*/
@Nullable
Object resolveAutowiredArgument(DependencyDescriptor descriptor, Class<?> paramType, String beanName,
protected Object resolveAutowiredArgument(MethodParameter param, String beanName,
@Nullable Set<String> autowiredBeanNames, TypeConverter typeConverter, boolean fallback) {
Class<?> paramType = param.getParameterType();
if (InjectionPoint.class.isAssignableFrom(paramType)) {
InjectionPoint injectionPoint = currentInjectionPoint.get();
if (injectionPoint == null) {
throw new IllegalStateException("No current InjectionPoint available for " + descriptor);
throw new IllegalStateException("No current InjectionPoint available for " + param);
}
return injectionPoint;
}
try {
return this.beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
return this.beanFactory.resolveDependency(
new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
}
catch (NoUniqueBeanDefinitionException ex) {
throw ex;
@@ -931,31 +908,6 @@ class ConstructorResolver {
}
}
private void setShortcutIfPossible(
ConstructorDependencyDescriptor descriptor, Class<?> paramType, Set<String> autowiredBeanNames) {
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (this.beanFactory.containsBean(autowiredBeanName) &&
this.beanFactory.isTypeMatch(autowiredBeanName, paramType)) {
descriptor.setShortcut(autowiredBeanName);
}
}
}
private void registerDependentBeans(
Executable executable, String beanName, Set<String> autowiredBeanNames) {
for (String autowiredBeanName : autowiredBeanNames) {
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName + "' via " +
(executable instanceof Constructor ? "constructor" : "factory method") +
" to bean named '" + autowiredBeanName + "'");
}
}
}
static InjectionPoint setCurrentInjectionPoint(@Nullable InjectionPoint injectionPoint) {
InjectionPoint old = currentInjectionPoint.get();
if (injectionPoint != null) {
@@ -1054,35 +1006,4 @@ class ConstructorResolver {
}
}
/**
* DependencyDescriptor marker for constructor arguments,
* for differentiating between a provided DependencyDescriptor instance
* and an internally built DependencyDescriptor for autowiring purposes.
*/
@SuppressWarnings("serial")
private static class ConstructorDependencyDescriptor extends DependencyDescriptor {
@Nullable
private volatile String shortcut;
public ConstructorDependencyDescriptor(MethodParameter methodParameter, boolean required) {
super(methodParameter, required);
}
public void setShortcut(@Nullable String shortcut) {
this.shortcut = shortcut;
}
public boolean hasShortcut() {
return (this.shortcut != null);
}
@Override
public Object resolveShortcut(BeanFactory beanFactory) {
String shortcut = this.shortcut;
return (shortcut != null ? beanFactory.getBean(shortcut, getDependencyType()) : null);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -961,7 +961,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
@@ -447,17 +447,17 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
}
String canonicalName = canonicalName(beanName);
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null || dependentBeans.isEmpty()) {
if (dependentBeans == null) {
return false;
}
if (dependentBeans.contains(dependentBeanName)) {
return true;
}
if (alreadySeen == null) {
alreadySeen = new HashSet<>();
}
alreadySeen.add(beanName);
for (String transitiveDependency : dependentBeans) {
if (alreadySeen == null) {
alreadySeen = new HashSet<>();
}
alreadySeen.add(beanName);
if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -112,7 +112,7 @@ public class LookupOverride extends MethodOverride {
@Override
public int hashCode() {
return super.hashCode() * 29 + ObjectUtils.nullSafeHashCode(this.beanName);
return (29 * super.hashCode() + ObjectUtils.nullSafeHashCode(this.beanName));
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -506,12 +506,23 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
if (isExternallyManagedInitMethod(initMethod)) {
return true;
}
return hasAnyExternallyManagedMethod(this.externallyManagedInitMethods, initMethod);
if (this.externallyManagedInitMethods != null) {
for (String candidate : this.externallyManagedInitMethods) {
int indexOfDot = candidate.lastIndexOf('.');
if (indexOfDot >= 0) {
String methodName = candidate.substring(indexOfDot + 1);
if (methodName.equals(initMethod)) {
return true;
}
}
}
}
return false;
}
}
/**
* Get all externally managed initialization methods (as an immutable Set).
* Return all externally managed initialization methods (as an immutable Set).
* <p>See {@link #registerExternallyManagedInitMethod} for details
* regarding the format for the initialization methods in the returned set.
* @since 5.3.11
@@ -572,23 +583,19 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
if (isExternallyManagedDestroyMethod(destroyMethod)) {
return true;
}
return hasAnyExternallyManagedMethod(this.externallyManagedDestroyMethods, destroyMethod);
}
}
private static boolean hasAnyExternallyManagedMethod(Set<String> candidates, String methodName) {
if (candidates != null) {
for (String candidate : candidates) {
int indexOfDot = candidate.lastIndexOf('.');
if (indexOfDot > 0) {
String candidateMethodName = candidate.substring(indexOfDot + 1);
if (candidateMethodName.equals(methodName)) {
return true;
if (this.externallyManagedDestroyMethods != null) {
for (String candidate : this.externallyManagedDestroyMethods) {
int indexOfDot = candidate.lastIndexOf('.');
if (indexOfDot >= 0) {
String methodName = candidate.substring(indexOfDot + 1);
if (methodName.equals(destroyMethod)) {
return true;
}
}
}
}
return false;
}
return false;
}
/**
@@ -1271,11 +1271,10 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("rod", bd);
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("rod2", bd2);
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
.isThrownBy(() -> lbf.autowire(ConstructorDependency.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false))
.withMessageContaining("rod")
.withMessageContaining("rod2");
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
lbf.autowire(ConstructorDependency.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false))
.withMessageContaining("rod")
.withMessageContaining("rod2");
}
@Test
@@ -1337,12 +1336,11 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
bd2.setDependsOn("tb1");
lbf.registerBeanDefinition("tb2", bd2);
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> lbf.preInstantiateSingletons())
.withMessageContaining("Circular")
.withMessageContaining("'tb2'")
.withMessageContaining("'tb1'");
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() ->
lbf.preInstantiateSingletons())
.withMessageContaining("Circular")
.withMessageContaining("'tb2'")
.withMessageContaining("'tb1'");
}
@Test
@@ -1356,12 +1354,11 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd3 = new RootBeanDefinition(TestBean.class);
bd3.setDependsOn("tb1");
lbf.registerBeanDefinition("tb3", bd3);
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(lbf::preInstantiateSingletons)
.withMessageContaining("Circular")
.withMessageContaining("'tb3'")
.withMessageContaining("'tb1'");
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
lbf::preInstantiateSingletons)
.withMessageContaining("Circular")
.withMessageContaining("'tb3'")
.withMessageContaining("'tb1'");
}
@Test
@@ -1496,11 +1493,10 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd2 = new RootBeanDefinition(HighPriorityTestBean.class);
lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2);
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class)
.isThrownBy(() -> lbf.getBean(TestBean.class))
.withMessageContaining("Multiple beans found with the same priority")
.withMessageContaining("5"); // conflicting priority
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(() ->
lbf.getBean(TestBean.class))
.withMessageContaining("Multiple beans found with the same priority")
.withMessageContaining("5"); // conflicting priority
}
@Test
@@ -1702,9 +1698,9 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2);
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class)
.isThrownBy(() -> lbf.getBean(ConstructorDependency.class, 42))
.withMessageContaining("more than one 'primary'");
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(() ->
lbf.getBean(ConstructorDependency.class, 42))
.withMessageContaining("more than one 'primary'");
}
@Test
@@ -1885,11 +1881,10 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("test", bd);
lbf.registerBeanDefinition("spouse", bd2);
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
.isThrownBy(() -> lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true))
.withMessageContaining("test")
.withMessageContaining("spouse");
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true))
.withMessageContaining("test")
.withMessageContaining("spouse");
}
@Test
@@ -1951,11 +1946,10 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd2 = new RootBeanDefinition(HighPriorityTestBean.class);
lbf.registerBeanDefinition("test", bd);
lbf.registerBeanDefinition("spouse", bd2);
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
.isThrownBy(() -> lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true))
.withCauseExactlyInstanceOf(NoUniqueBeanDefinitionException.class)
.withMessageContaining("5");
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true))
.withCauseExactlyInstanceOf(NoUniqueBeanDefinitionException.class)
.withMessageContaining("5");
}
@Test
@@ -2191,21 +2185,19 @@ class DefaultListableBeanFactoryTests {
@Test
void beanDefinitionWithInterface() {
lbf.registerBeanDefinition("test", new RootBeanDefinition(ITestBean.class));
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> lbf.getBean("test"))
.withMessageContaining("interface")
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("test"));
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() ->
lbf.getBean("test"))
.withMessageContaining("interface")
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("test"));
}
@Test
void beanDefinitionWithAbstractClass() {
lbf.registerBeanDefinition("test", new RootBeanDefinition(AbstractBeanFactory.class));
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> lbf.getBean("test"))
.withMessageContaining("abstract")
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("test"));
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() ->
lbf.getBean("test"))
.withMessageContaining("abstract")
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("test"));
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -28,32 +28,36 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Chris Beams
* @since 04.07.2006
*/
class DefaultSingletonBeanRegistryTests {
private final DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry();
public class DefaultSingletonBeanRegistryTests {
@Test
void singletons() {
public void testSingletons() {
DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry();
TestBean tb = new TestBean();
beanRegistry.registerSingleton("tb", tb);
assertThat(beanRegistry.getSingleton("tb")).isSameAs(tb);
TestBean tb2 = (TestBean) beanRegistry.getSingleton("tb2", TestBean::new);
TestBean tb2 = (TestBean) beanRegistry.getSingleton("tb2", () -> new TestBean());
assertThat(beanRegistry.getSingleton("tb2")).isSameAs(tb2);
assertThat(beanRegistry.getSingleton("tb")).isSameAs(tb);
assertThat(beanRegistry.getSingleton("tb2")).isSameAs(tb2);
assertThat(beanRegistry.getSingletonCount()).isEqualTo(2);
assertThat(beanRegistry.getSingletonNames()).containsExactly("tb", "tb2");
String[] names = beanRegistry.getSingletonNames();
assertThat(names.length).isEqualTo(2);
assertThat(names[0]).isEqualTo("tb");
assertThat(names[1]).isEqualTo("tb2");
beanRegistry.destroySingletons();
assertThat(beanRegistry.getSingletonCount()).isZero();
assertThat(beanRegistry.getSingletonNames()).isEmpty();
assertThat(beanRegistry.getSingletonCount()).isEqualTo(0);
assertThat(beanRegistry.getSingletonNames().length).isEqualTo(0);
}
@Test
void disposableBean() {
public void testDisposableBean() {
DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry();
DerivedTestBean tb = new DerivedTestBean();
beanRegistry.registerSingleton("tb", tb);
beanRegistry.registerDisposableBean("tb", tb);
@@ -61,16 +65,21 @@ class DefaultSingletonBeanRegistryTests {
assertThat(beanRegistry.getSingleton("tb")).isSameAs(tb);
assertThat(beanRegistry.getSingletonCount()).isEqualTo(1);
assertThat(beanRegistry.getSingletonNames()).containsExactly("tb");
String[] names = beanRegistry.getSingletonNames();
assertThat(names.length).isEqualTo(1);
assertThat(names[0]).isEqualTo("tb");
assertThat(tb.wasDestroyed()).isFalse();
beanRegistry.destroySingletons();
assertThat(beanRegistry.getSingletonCount()).isZero();
assertThat(beanRegistry.getSingletonNames()).isEmpty();
assertThat(beanRegistry.getSingletonCount()).isEqualTo(0);
assertThat(beanRegistry.getSingletonNames().length).isEqualTo(0);
assertThat(tb.wasDestroyed()).isTrue();
}
@Test
void dependentRegistration() {
public void testDependentRegistration() {
DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry();
beanRegistry.registerDependentBean("a", "b");
beanRegistry.registerDependentBean("b", "c");
beanRegistry.registerDependentBean("c", "b");
@@ -4,27 +4,25 @@
<beans default-lazy-init="true">
<bean name="beta" class="org.springframework.beans.factory.FactoryBeanTests$Beta" autowire="byType">
<property name="name" value="${myName}"/>
<property name="name" value="${myName}"/>
</bean>
<bean id="alpha" class="org.springframework.beans.factory.FactoryBeanTests$Alpha" autowire="byType"/>
<bean id="gamma" class="org.springframework.beans.factory.FactoryBeanTests$Gamma"/>
<bean id="betaFactory" class="org.springframework.beans.factory.FactoryBeanTests$BetaFactoryBean" autowire="constructor">
<property name="beta" ref="beta"/>
</bean>
<bean id="betaFactory" class="org.springframework.beans.factory.FactoryBeanTests$BetaFactoryBean" autowire="constructor">
<property name="beta" ref="beta"/>
</bean>
<bean id="gammaFactory" factory-bean="${gammaFactory}" factory-method="${gamma}"/>
<bean id="gammaFactory" factory-bean="betaFactory" factory-method="getGamma"/>
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties">
<props>
<prop key="myName">yourName</prop>
<prop key="gammaFactory">betaFactory</prop>
<prop key="gamma">getGamma</prop>
</props>
</property>
</bean>
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties">
<props>
<prop key="myName">yourName</prop>
</props>
</property>
</bean>
</beans>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -477,7 +477,7 @@ public class TestBean implements BeanNameAware, BeanFactoryAware, ITestBean, IOt
@Override
public int hashCode() {
return TestBean.class.hashCode();
return this.age;
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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,8 +59,8 @@ public class CaffeineCache extends AbstractValueAdaptingCache {
* given internal {@link com.github.benmanes.caffeine.cache.Cache} to use.
* @param name the name of the cache
* @param cache the backing Caffeine Cache instance
* @param allowNullValues whether to accept and convert {@code null} values
* for this cache
* @param allowNullValues whether to accept and convert {@code null}
* values for this cache
*/
public CaffeineCache(String name, com.github.benmanes.caffeine.cache.Cache<Object, Object> cache,
boolean allowNullValues) {
@@ -86,7 +86,7 @@ public class CaffeineCache extends AbstractValueAdaptingCache {
@SuppressWarnings("unchecked")
@Override
@Nullable
public <T> T get(Object key, Callable<T> valueLoader) {
public <T> T get(Object key, final Callable<T> valueLoader) {
return (T) fromStoreValue(this.cache.get(key, new LoadFunction(valueLoader)));
}
@@ -106,7 +106,7 @@ public class CaffeineCache extends AbstractValueAdaptingCache {
@Override
@Nullable
public ValueWrapper putIfAbsent(Object key, @Nullable Object value) {
public ValueWrapper putIfAbsent(Object key, @Nullable final Object value) {
PutIfAbsentFunction callable = new PutIfAbsentFunction(value);
Object result = this.cache.get(key, callable);
return (callable.called ? null : toValueWrapper(result));
@@ -140,7 +140,7 @@ public class CaffeineCache extends AbstractValueAdaptingCache {
@Nullable
private final Object value;
boolean called;
private boolean called;
public PutIfAbsentFunction(@Nullable Object value) {
this.value = value;
@@ -159,17 +159,16 @@ public class CaffeineCache extends AbstractValueAdaptingCache {
private final Callable<?> valueLoader;
public LoadFunction(Callable<?> valueLoader) {
Assert.notNull(valueLoader, "Callable must not be null");
this.valueLoader = valueLoader;
}
@Override
public Object apply(Object key) {
public Object apply(Object o) {
try {
return toStoreValue(this.valueLoader.call());
}
catch (Exception ex) {
throw new ValueRetrievalException(key, this.valueLoader, ex);
throw new ValueRetrievalException(o, this.valueLoader, ex);
}
}
}
@@ -110,7 +110,7 @@ public class CaffeineCacheManager implements CacheManager {
* Set the Caffeine to use for building each individual
* {@link CaffeineCache} instance.
* @see #createNativeCaffeineCache
* @see Caffeine#build()
* @see com.github.benmanes.caffeine.cache.Caffeine#build()
*/
public void setCaffeine(Caffeine<Object, Object> caffeine) {
Assert.notNull(caffeine, "Caffeine must not be null");
@@ -121,7 +121,7 @@ public class CaffeineCacheManager implements CacheManager {
* Set the {@link CaffeineSpec} to use for building each individual
* {@link CaffeineCache} instance.
* @see #createNativeCaffeineCache
* @see Caffeine#from(CaffeineSpec)
* @see com.github.benmanes.caffeine.cache.Caffeine#from(CaffeineSpec)
*/
public void setCaffeineSpec(CaffeineSpec caffeineSpec) {
doSetCaffeine(Caffeine.from(caffeineSpec));
@@ -132,7 +132,7 @@ public class CaffeineCacheManager implements CacheManager {
* individual {@link CaffeineCache} instance. The given value needs to
* comply with Caffeine's {@link CaffeineSpec} (see its javadoc).
* @see #createNativeCaffeineCache
* @see Caffeine#from(String)
* @see com.github.benmanes.caffeine.cache.Caffeine#from(String)
*/
public void setCacheSpecification(String cacheSpecification) {
doSetCaffeine(Caffeine.from(cacheSpecification));
@@ -149,7 +149,7 @@ public class CaffeineCacheManager implements CacheManager {
* Set the Caffeine CacheLoader to use for building each individual
* {@link CaffeineCache} instance, turning it into a LoadingCache.
* @see #createNativeCaffeineCache
* @see Caffeine#build(CacheLoader)
* @see com.github.benmanes.caffeine.cache.Caffeine#build(CacheLoader)
* @see com.github.benmanes.caffeine.cache.LoadingCache
*/
public void setCacheLoader(CacheLoader<Object, Object> cacheLoader) {
@@ -189,11 +189,13 @@ public class CaffeineCacheManager implements CacheManager {
@Override
@Nullable
public Cache getCache(String name) {
Cache cache = this.cacheMap.get(name);
if (cache == null && this.dynamic) {
cache = this.cacheMap.computeIfAbsent(name, this::createCaffeineCache);
if (this.dynamic) {
Cache cache = this.cacheMap.get(name);
return (cache != null) ? cache : this.cacheMap.computeIfAbsent(name, this::createCaffeineCache);
}
else {
return this.cacheMap.get(name);
}
return cache;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -38,17 +38,19 @@ public class CaffeineCacheManagerTests {
@Test
public void testDynamicMode() {
CacheManager cm = new CaffeineCacheManager();
Cache cache1 = cm.getCache("c1");
assertThat(cache1).isInstanceOf(CaffeineCache.class);
boolean condition2 = cache1 instanceof CaffeineCache;
assertThat(condition2).isTrue();
Cache cache1again = cm.getCache("c1");
assertThat(cache1).isSameAs(cache1again);
Cache cache2 = cm.getCache("c2");
assertThat(cache2).isInstanceOf(CaffeineCache.class);
boolean condition1 = cache2 instanceof CaffeineCache;
assertThat(condition1).isTrue();
Cache cache2again = cm.getCache("c2");
assertThat(cache2).isSameAs(cache2again);
Cache cache3 = cm.getCache("c3");
assertThat(cache3).isInstanceOf(CaffeineCache.class);
boolean condition = cache3 instanceof CaffeineCache;
assertThat(condition).isTrue();
Cache cache3again = cm.getCache("c3");
assertThat(cache3).isSameAs(cache3again);
@@ -60,23 +62,19 @@ public class CaffeineCacheManagerTests {
assertThat(cache1.get("key3").get()).isNull();
cache1.evict("key3");
assertThat(cache1.get("key3")).isNull();
assertThat(cache1.get("key3", () -> "value3")).isEqualTo("value3");
assertThat(cache1.get("key3", () -> "value3")).isEqualTo("value3");
cache1.evict("key3");
assertThat(cache1.get("key3", () -> (String) null)).isNull();
assertThat(cache1.get("key3", () -> (String) null)).isNull();
}
@Test
public void testStaticMode() {
CaffeineCacheManager cm = new CaffeineCacheManager("c1", "c2");
Cache cache1 = cm.getCache("c1");
assertThat(cache1).isInstanceOf(CaffeineCache.class);
boolean condition3 = cache1 instanceof CaffeineCache;
assertThat(condition3).isTrue();
Cache cache1again = cm.getCache("c1");
assertThat(cache1).isSameAs(cache1again);
Cache cache2 = cm.getCache("c2");
assertThat(cache2).isInstanceOf(CaffeineCache.class);
boolean condition2 = cache2 instanceof CaffeineCache;
assertThat(condition2).isTrue();
Cache cache2again = cm.getCache("c2");
assertThat(cache2).isSameAs(cache2again);
Cache cache3 = cm.getCache("c3");
@@ -93,11 +91,13 @@ public class CaffeineCacheManagerTests {
cm.setAllowNullValues(false);
Cache cache1x = cm.getCache("c1");
assertThat(cache1x).isInstanceOf(CaffeineCache.class);
assertThat(cache1x).isNotSameAs(cache1);
boolean condition1 = cache1x instanceof CaffeineCache;
assertThat(condition1).isTrue();
assertThat(cache1x != cache1).isTrue();
Cache cache2x = cm.getCache("c2");
assertThat(cache2x).isInstanceOf(CaffeineCache.class);
assertThat(cache2x).isNotSameAs(cache2);
boolean condition = cache2x instanceof CaffeineCache;
assertThat(condition).isTrue();
assertThat(cache2x != cache2).isTrue();
Cache cache3x = cm.getCache("c3");
assertThat(cache3x).isNull();
@@ -190,7 +190,7 @@ public class CaffeineCacheManagerTests {
assertThat(value.get()).isEqualTo("pong");
assertThatIllegalArgumentException().isThrownBy(() -> assertThat(cache1.get("foo")).isNull())
.withMessageContaining("I only know ping");
.withMessageContaining("I only know ping");
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -114,7 +114,7 @@ class QuartzSupportTests {
trigger.setName("myTrigger");
trigger.setJobDetail(jobDetail);
trigger.setStartDelay(1);
trigger.setRepeatInterval(100);
trigger.setRepeatInterval(500);
trigger.setRepeatCount(1);
trigger.afterPropertiesSet();
@@ -126,14 +126,14 @@ class QuartzSupportTests {
bean.start();
Thread.sleep(500);
assertThat(DummyJob.count).as("DummyJob should have been executed at least once.").isGreaterThan(0);
assertThat(DummyJob.count > 0).as("DummyJob should have been executed at least once.").isTrue();
assertThat(taskExecutor.count).isEqualTo(DummyJob.count);
bean.destroy();
}
@Test
@SuppressWarnings({"unchecked", "rawtypes"})
@SuppressWarnings({ "unchecked", "rawtypes" })
void jobDetailWithRunnableInsteadOfJob() {
JobDetailImpl jobDetail = new JobDetailImpl();
assertThatIllegalArgumentException().isThrownBy(() ->
@@ -156,7 +156,7 @@ class QuartzSupportTests {
trigger.setName("myTrigger");
trigger.setJobDetail(jobDetail);
trigger.setStartDelay(1);
trigger.setRepeatInterval(100);
trigger.setRepeatInterval(500);
trigger.setRepeatCount(1);
trigger.afterPropertiesSet();
@@ -168,7 +168,7 @@ class QuartzSupportTests {
Thread.sleep(500);
assertThat(DummyJobBean.param).isEqualTo(10);
assertThat(DummyJobBean.count).isGreaterThan(0);
assertThat(DummyJobBean.count > 0).isTrue();
bean.destroy();
}
@@ -190,7 +190,7 @@ class QuartzSupportTests {
trigger.setName("myTrigger");
trigger.setJobDetail(jobDetail);
trigger.setStartDelay(1);
trigger.setRepeatInterval(100);
trigger.setRepeatInterval(500);
trigger.setRepeatCount(1);
trigger.afterPropertiesSet();
@@ -203,7 +203,7 @@ class QuartzSupportTests {
Thread.sleep(500);
assertThat(DummyJob.param).isEqualTo(10);
assertThat(DummyJob.count).as("DummyJob should have been executed at least once.").isGreaterThan(0);
assertThat(DummyJob.count > 0).as("DummyJob should have been executed at least once.").isTrue();
bean.destroy();
}
@@ -225,7 +225,7 @@ class QuartzSupportTests {
trigger.setName("myTrigger");
trigger.setJobDetail(jobDetail);
trigger.setStartDelay(1);
trigger.setRepeatInterval(100);
trigger.setRepeatInterval(500);
trigger.setRepeatCount(1);
trigger.afterPropertiesSet();
@@ -239,7 +239,7 @@ class QuartzSupportTests {
Thread.sleep(500);
assertThat(DummyJob.param).isEqualTo(0);
assertThat(DummyJob.count).isEqualTo(0);
assertThat(DummyJob.count == 0).isTrue();
bean.destroy();
}
@@ -260,7 +260,7 @@ class QuartzSupportTests {
trigger.setName("myTrigger");
trigger.setJobDetail(jobDetail);
trigger.setStartDelay(1);
trigger.setRepeatInterval(100);
trigger.setRepeatInterval(500);
trigger.setRepeatCount(1);
trigger.afterPropertiesSet();
@@ -273,7 +273,7 @@ class QuartzSupportTests {
Thread.sleep(500);
assertThat(DummyJobBean.param).isEqualTo(10);
assertThat(DummyJobBean.count).isGreaterThan(0);
assertThat(DummyJobBean.count > 0).isTrue();
bean.destroy();
}
@@ -292,7 +292,7 @@ class QuartzSupportTests {
Thread.sleep(500);
assertThat(DummyJob.param).isEqualTo(10);
assertThat(DummyJob.count).as("DummyJob should have been executed at least once.").isGreaterThan(0);
assertThat(DummyJob.count > 0).as("DummyJob should have been executed at least once.").isTrue();
bean.destroy();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -23,20 +23,14 @@ import org.springframework.lang.Nullable;
/**
* Interface that defines common cache operations.
*
* <p>Serves as an SPI for Spring's annotation-based caching model
* ({@link org.springframework.cache.annotation.Cacheable} and co)
* as well as an API for direct usage in applications.
*
* <p><b>Note:</b> Due to the generic use of caching, it is recommended
* that implementations allow storage of {@code null} values
* (for example to cache methods that return {@code null}).
* <b>Note:</b> Due to the generic use of caching, it is recommended that
* implementations allow storage of {@code null} values (for example to
* cache methods that return {@code null}).
*
* @author Costin Leau
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 3.1
* @see CacheManager
* @see org.springframework.cache.annotation.Cacheable
*/
public interface Cache {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -175,9 +175,9 @@ public @interface Cacheable {
* <li>Only one cache may be specified</li>
* <li>No other cache-related operation can be combined</li>
* </ol>
* This is effectively a hint and the chosen cache provider might not actually
* support it in a synchronized fashion. Check your provider documentation for
* more details on the actual semantics.
* This is effectively a hint and the actual cache provider that you are
* using may not support it in a synchronized fashion. Check your provider
* documentation for more details on the actual semantics.
* @since 4.3
* @see org.springframework.cache.Cache#get(Object, Callable)
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -166,7 +166,13 @@ public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderA
public Cache getCache(String name) {
Cache cache = this.cacheMap.get(name);
if (cache == null && this.dynamic) {
cache = this.cacheMap.computeIfAbsent(name, this::createConcurrentMapCache);
synchronized (this.cacheMap) {
cache = this.cacheMap.get(name);
if (cache == null) {
cache = createConcurrentMapCache(name);
this.cacheMap.put(name, cache);
}
}
}
return cache;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -82,12 +82,12 @@ public abstract class AbstractCacheInvoker {
* Execute {@link Cache#put(Object, Object)} on the specified {@link Cache}
* and invoke the error handler if an exception occurs.
*/
protected void doPut(Cache cache, Object key, @Nullable Object value) {
protected void doPut(Cache cache, Object key, @Nullable Object result) {
try {
cache.put(key, value);
cache.put(key, result);
}
catch (RuntimeException ex) {
getErrorHandler().handleCachePutError(ex, cache, key, value);
getErrorHandler().handleCachePutError(ex, cache, key, result);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -214,7 +214,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
@Override
public void afterSingletonsInstantiated() {
if (getCacheResolver() == null) {
// Lazily initialize cache resolver via default cache manager
// Lazily initialize cache resolver via default cache manager...
Assert.state(this.beanFactory != null, "CacheResolver or BeanFactory must be set on cache aspect");
try {
setCacheManager(this.beanFactory.getBean(CacheManager.class));
@@ -307,22 +307,22 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
}
/**
* Retrieve a bean with the specified name and type.
* Used to resolve services that are referenced by name in a {@link CacheOperation}.
* @param name the name of the bean, as defined by the cache operation
* @param serviceType the type expected by the operation's service reference
* @return the bean matching the expected type, qualified by the given name
* Return a bean with the specified name and type. Used to resolve services that
* are referenced by name in a {@link CacheOperation}.
* @param beanName the name of the bean, as defined by the operation
* @param expectedType type for the bean
* @return the bean matching that name
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException if such bean does not exist
* @see CacheOperation#getKeyGenerator()
* @see CacheOperation#getCacheManager()
* @see CacheOperation#getCacheResolver()
*/
protected <T> T getBean(String name, Class<T> serviceType) {
protected <T> T getBean(String beanName, Class<T> expectedType) {
if (this.beanFactory == null) {
throw new IllegalStateException(
"BeanFactory must be set on cache aspect for " + serviceType.getSimpleName() + " retrieval");
"BeanFactory must be set on cache aspect for " + expectedType.getSimpleName() + " retrieval");
}
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(this.beanFactory, serviceType, name);
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(this.beanFactory, expectedType, beanName);
}
/**
@@ -388,20 +388,21 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
}
}
else {
// No caching required, just call the underlying method
// No caching required, only call the underlying method
return invokeOperation(invoker);
}
}
// Process any early evictions
processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
CacheOperationExpressionEvaluator.NO_RESULT);
// Check if we have a cached value matching the conditions
// Check if we have a cached item matching the conditions
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
// Collect puts from any @Cacheable miss, if no cached value is found
List<CachePutRequest> cachePutRequests = new ArrayList<>(1);
// Collect puts from any @Cacheable miss, if no cached item is found
List<CachePutRequest> cachePutRequests = new ArrayList<>();
if (cacheHit == null) {
collectPutRequests(contexts.get(CacheableOperation.class),
CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);
@@ -468,7 +469,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
private boolean hasCachePut(CacheOperationContexts contexts) {
// Evaluate the conditions *without* the result object because we don't have it yet...
Collection<CacheOperationContext> cachePutContexts = contexts.get(CachePutOperation.class);
Collection<CacheOperationContext> excluded = new ArrayList<>(1);
Collection<CacheOperationContext> excluded = new ArrayList<>();
for (CacheOperationContext context : cachePutContexts) {
try {
if (!context.isConditionPassing(CacheOperationExpressionEvaluator.RESULT_UNAVAILABLE)) {
@@ -521,9 +522,9 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
}
/**
* Find a cached value only for {@link CacheableOperation} that passes the condition.
* Find a cached item only for {@link CacheableOperation} that passes the condition.
* @param contexts the cacheable operations
* @return a {@link Cache.ValueWrapper} holding the cached value,
* @return a {@link Cache.ValueWrapper} holding the cached item,
* or {@code null} if none is found
*/
@Nullable
@@ -548,9 +549,9 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
/**
* Collect the {@link CachePutRequest} for all {@link CacheOperation} using
* the specified result value.
* the specified result item.
* @param contexts the contexts to handle
* @param result the result value (never {@code null})
* @param result the result item (never {@code null})
* @param putRequests the collection to update
*/
private void collectPutRequests(Collection<CacheOperationContext> contexts,
@@ -640,22 +641,21 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
if (syncEnabled) {
if (this.contexts.size() > 1) {
throw new IllegalStateException(
"A sync=true operation cannot be combined with other cache operations on '" + method + "'");
"@Cacheable(sync=true) cannot be combined with other cache operations on '" + method + "'");
}
if (cacheOperationContexts.size() > 1) {
throw new IllegalStateException(
"Only one sync=true operation is allowed on '" + method + "'");
"Only one @Cacheable(sync=true) entry is allowed on '" + method + "'");
}
CacheOperationContext cacheOperationContext = cacheOperationContexts.iterator().next();
CacheOperation operation = cacheOperationContext.getOperation();
CacheableOperation operation = (CacheableOperation) cacheOperationContext.getOperation();
if (cacheOperationContext.getCaches().size() > 1) {
throw new IllegalStateException(
"A sync=true operation is restricted to a single cache on '" + operation + "'");
"@Cacheable(sync=true) only allows a single cache on '" + operation + "'");
}
if (operation instanceof CacheableOperation &&
StringUtils.hasText(((CacheableOperation) operation).getUnless())) {
if (StringUtils.hasText(operation.getUnless())) {
throw new IllegalStateException(
"A sync=true operation does not support the unless attribute on '" + operation + "'");
"@Cacheable(sync=true) does not support unless attribute on '" + operation + "'");
}
return true;
}
@@ -722,7 +722,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
this.args = extractArgs(metadata.method, args);
this.target = target;
this.caches = CacheAspectSupport.this.getCaches(this, metadata.cacheResolver);
this.cacheNames = prepareCacheNames(this.caches);
this.cacheNames = createCacheNames(this.caches);
}
@Override
@@ -810,8 +810,8 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
return this.cacheNames;
}
private Collection<String> prepareCacheNames(Collection<? extends Cache> caches) {
Collection<String> names = new ArrayList<>(caches.size());
private Collection<String> createCacheNames(Collection<? extends Cache> caches) {
Collection<String> names = new ArrayList<>();
for (Cache cache : caches) {
names.add(cache.getName());
}
@@ -885,13 +885,13 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
}
}
/**
* Internal holder class for recording that a cache method was invoked.
*/
private static class InvocationAwareResult {
boolean invoked;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -24,16 +24,14 @@ import org.springframework.cache.Cache;
/**
* Simple cache manager working against a given collection of caches.
* Useful for testing or simple caching declarations.
*
* <p>When using this implementation directly, i.e. not via a regular
* <p>
* When using this implementation directly, i.e. not via a regular
* bean registration, {@link #initializeCaches()} should be invoked
* to initialize its internal state once the
* {@linkplain #setCaches(Collection) caches have been provided}.
*
* @author Costin Leau
* @since 3.1
* @see NoOpCache
* @see org.springframework.cache.concurrent.ConcurrentMapCache
*/
public class SimpleCacheManager extends AbstractCacheManager {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -65,7 +65,7 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = getApplicationStartup().start("spring.context.annotated-bean-reader.create");
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
@@ -163,7 +163,7 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
@Override
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
StartupStep registerComponentClass = getApplicationStartup().start("spring.context.component-classes.register")
StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register")
.tag("classes", () -> Arrays.toString(componentClasses));
this.reader.register(componentClasses);
registerComponentClass.end();
@@ -180,7 +180,7 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
@Override
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
StartupStep scanPackages = getApplicationStartup().start("spring.context.base-packages.scan")
StartupStep scanPackages = this.getApplicationStartup().start("spring.context.base-packages.scan")
.tag("packages", () -> Arrays.toString(basePackages));
this.scanner.scan(basePackages);
scanPackages.end();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -39,7 +39,6 @@ final class BeanMethod extends ConfigurationMethod {
super(metadata, configurationClass);
}
@Override
public void validate(ProblemReporter problemReporter) {
if (getMetadata().isStatic()) {
@@ -56,9 +55,9 @@ final class BeanMethod extends ConfigurationMethod {
}
@Override
public boolean equals(@Nullable Object other) {
return (this == other || (other instanceof BeanMethod &&
this.metadata.equals(((BeanMethod) other).metadata)));
public boolean equals(@Nullable Object obj) {
return ((this == obj) || ((obj instanceof BeanMethod) &&
this.metadata.equals(((BeanMethod) obj).metadata)));
}
@Override
@@ -71,7 +70,6 @@ final class BeanMethod extends ConfigurationMethod {
return "BeanMethod: " + this.metadata;
}
private class NonOverridableMethodError extends Problem {
NonOverridableMethodError() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -329,8 +329,8 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
* @return {@code true} if the bean can be registered as-is;
* {@code false} if it should be skipped because there is an
* existing, compatible bean definition for the specified name
* @throws IllegalStateException if an existing, incompatible bean definition
* has been found for the specified name
* @throws ConflictingBeanDefinitionException if an existing, incompatible
* bean definition has been found for the specified name
*/
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
if (!this.registry.containsBeanDefinition(beanName)) {
@@ -354,16 +354,16 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
* the given existing bean definition.
* <p>The default implementation considers them as compatible when the existing
* bean definition comes from the same source or from a non-scanning source.
* @param newDef the new bean definition, originated from scanning
* @param existingDef the existing bean definition, potentially an
* @param newDefinition the new bean definition, originated from scanning
* @param existingDefinition the existing bean definition, potentially an
* explicitly defined one or a previously generated one from scanning
* @return whether the definitions are considered as compatible, with the
* new definition to be skipped in favor of the existing definition
*/
protected boolean isCompatible(BeanDefinition newDef, BeanDefinition existingDef) {
return (!(existingDef instanceof ScannedGenericBeanDefinition) || // explicitly registered overriding bean
(newDef.getSource() != null && newDef.getSource().equals(existingDef.getSource())) || // scanned same file twice
newDef.equals(existingDef)); // scanned equivalent class twice
protected boolean isCompatible(BeanDefinition newDefinition, BeanDefinition existingDefinition) {
return (!(existingDefinition instanceof ScannedGenericBeanDefinition) || // explicitly registered overriding bean
(newDefinition.getSource() != null && newDefinition.getSource().equals(existingDefinition.getSource())) || // scanned same file twice
newDefinition.equals(existingDefinition)); // scanned equivalent class twice
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -424,7 +424,6 @@ class ConfigurationClassBeanDefinitionReader {
public ConfigurationClassBeanDefinition(RootBeanDefinition original,
ConfigurationClass configClass, MethodMetadata beanMethodMetadata, String derivedBeanName) {
super(original);
this.annotationMetadata = configClass.getMetadata();
this.factoryMethodMetadata = beanMethodMetadata;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -409,14 +409,11 @@ class ConfigurationClassParser {
this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
if (asmMethods.size() >= beanMethods.size()) {
Set<MethodMetadata> candidateMethods = new LinkedHashSet<>(beanMethods);
Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
for (MethodMetadata asmMethod : asmMethods) {
for (Iterator<MethodMetadata> it = candidateMethods.iterator(); it.hasNext();) {
MethodMetadata beanMethod = it.next();
for (MethodMetadata beanMethod : beanMethods) {
if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
selectedMethods.add(beanMethod);
it.remove();
break;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2012 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,8 @@ import org.springframework.instrument.classloading.LoadTimeWeaver;
/**
* Interface to be implemented by
* {@link org.springframework.context.annotation.Configuration @Configuration}
* classes annotated with {@link EnableLoadTimeWeaving @EnableLoadTimeWeaving}
* that wish to customize the {@link LoadTimeWeaver} instance to be used.
* classes annotated with {@link EnableLoadTimeWeaving @EnableLoadTimeWeaving} that wish to
* customize the {@link LoadTimeWeaver} instance to be used.
*
* <p>See {@link org.springframework.scheduling.annotation.EnableAsync @EnableAsync}
* for usage examples and information on how a default {@code LoadTimeWeaver}
@@ -36,9 +36,9 @@ import org.springframework.instrument.classloading.LoadTimeWeaver;
public interface LoadTimeWeavingConfigurer {
/**
* Create, configure and return the {@code LoadTimeWeaver} instance to be used.
* Note that it is unnecessary to annotate this method with {@code @Bean}
* because the object returned will automatically be registered as a bean by
* Create, configure and return the {@code LoadTimeWeaver} instance to be used. Note
* that it is unnecessary to annotate this method with {@code @Bean}, because the
* object returned will automatically be registered as a bean by
* {@link LoadTimeWeavingConfiguration#loadTimeWeaver()}
*/
LoadTimeWeaver getLoadTimeWeaver();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -367,7 +367,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
* Return the target bean instance to use.
*/
protected Object getTargetBean() {
Assert.notNull(this.applicationContext, "ApplicationContext must not be null");
Assert.notNull(this.applicationContext, "ApplicationContext must no be null");
return this.applicationContext.getBean(this.beanName);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -79,11 +79,10 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM
* to invoke each listener with.
* <p>Default is equivalent to {@link org.springframework.core.task.SyncTaskExecutor},
* executing all listeners synchronously in the calling thread.
* <p>Consider specifying an asynchronous task executor here to not block the caller
* until all listeners have been executed. However, note that asynchronous execution
* will not participate in the caller's thread context (class loader, transaction context)
* unless the TaskExecutor explicitly supports this.
* @since 2.0
* <p>Consider specifying an asynchronous task executor here to not block the
* caller until all listeners have been executed. However, note that asynchronous
* execution will not participate in the caller's thread context (class loader,
* transaction association) unless the TaskExecutor explicitly supports this.
* @see org.springframework.core.task.SyncTaskExecutor
* @see org.springframework.core.task.SimpleAsyncTaskExecutor
*/
@@ -93,7 +92,6 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM
/**
* Return the current task executor for this multicaster.
* @since 2.0
*/
@Nullable
protected Executor getTaskExecutor() {
@@ -749,8 +749,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null &&
beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
@@ -1083,9 +1082,6 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
// Let subclasses do some final clean-up if they wish...
onClose();
// Reset common introspection caches to avoid class reference leaks.
resetCommonCaches();
// Reset local application listeners to pre-refresh state.
if (this.earlyApplicationListeners != null) {
this.applicationListeners.clear();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -20,7 +20,6 @@ import java.io.IOException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.BeanDefinitionDocumentReader;
import org.springframework.beans.factory.xml.ResourceEntityResolver;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
@@ -85,7 +84,7 @@ public abstract class AbstractXmlApplicationContext extends AbstractRefreshableC
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(getEnvironment());
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
@@ -96,13 +95,12 @@ public abstract class AbstractXmlApplicationContext extends AbstractRefreshableC
}
/**
* Initialize the bean definition reader used for loading the bean definitions
* of this context. The default implementation sets the validating flag.
* Initialize the bean definition reader used for loading the bean
* definitions of this context. Default implementation is empty.
* <p>Can be overridden in subclasses, e.g. for turning off XML validation
* or using a different {@link BeanDefinitionDocumentReader} implementation.
* or using a different XmlBeanDefinitionParser implementation.
* @param reader the bean definition reader used by this context
* @see XmlBeanDefinitionReader#setValidating
* @see XmlBeanDefinitionReader#setDocumentReaderClass
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setDocumentReaderClass
*/
protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
reader.setValidating(this.validating);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -21,8 +21,6 @@ import java.security.ProtectionDomain;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.DecoratingClassLoader;
import org.springframework.core.OverridingClassLoader;
import org.springframework.core.SmartClassLoader;
@@ -47,26 +45,15 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
}
@Nullable
private static final Method findLoadedClassMethod;
private static Method findLoadedClassMethod;
static {
// Try to enable findLoadedClass optimization which allows us to selectively
// override classes that have not been loaded yet. If not accessible, we will
// always override requested classes, even when the classes have been loaded
// by the parent ClassLoader already and cannot be transformed anymore anyway.
Method method = null;
try {
method = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
ReflectionUtils.makeAccessible(method);
findLoadedClassMethod = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
}
catch (Throwable ex) {
// Typically a JDK 9+ InaccessibleObjectException...
// Avoid through JVM startup with --add-opens=java.base/java.lang=ALL-UNNAMED
LogFactory.getLog(ContextTypeMatchClassLoader.class).debug(
"ClassLoader.findLoadedClass not accessible -> will always override requested class", ex);
catch (NoSuchMethodException ex) {
throw new IllegalStateException("Invalid [java.lang.ClassLoader] class: no 'findLoadedClass' method defined!");
}
findLoadedClassMethod = method;
}
@@ -109,14 +96,13 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
if (isExcluded(className) || ContextTypeMatchClassLoader.this.isExcluded(className)) {
return false;
}
if (findLoadedClassMethod != null) {
ClassLoader parent = getParent();
while (parent != null) {
if (ReflectionUtils.invokeMethod(findLoadedClassMethod, parent, className) != null) {
return false;
}
parent = parent.getParent();
ReflectionUtils.makeAccessible(findLoadedClassMethod);
ClassLoader parent = getParent();
while (parent != null) {
if (ReflectionUtils.invokeMethod(findLoadedClassMethod, parent, className) != null) {
return false;
}
parent = parent.getParent();
}
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -64,10 +64,9 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
/**
* Specify the maximum time allotted in milliseconds for the shutdown of any
* phase (group of {@link SmartLifecycle} beans with the same 'phase' value).
* <p>The default value is 30000 milliseconds (30 seconds).
* @see SmartLifecycle#getPhase()
* Specify the maximum time allotted in milliseconds for the shutdown of
* any phase (group of SmartLifecycle beans with the same 'phase' value).
* <p>The default value is 30 seconds.
*/
public void setTimeoutPerShutdownPhase(long timeoutPerShutdownPhase) {
this.timeoutPerShutdownPhase = timeoutPerShutdownPhase;
@@ -28,8 +28,8 @@ import org.springframework.scheduling.config.ScheduledTaskRegistrar;
/**
* Annotation that marks a method to be scheduled. Exactly one of the
* {@link #cron}, {@link #fixedDelay}, or {@link #fixedRate} attributes
* must be specified.
* {@link #cron}, {@link #fixedDelay}, or {@link #fixedRate} attributes must be
* specified.
*
* <p>The annotated method must expect no arguments. It will typically have
* a {@code void} return type; if not, the returned value will be ignored
@@ -40,12 +40,6 @@ import org.springframework.scheduling.config.ScheduledTaskRegistrar;
* done manually or, more conveniently, through the {@code <task:annotation-driven/>}
* XML element or {@link EnableScheduling @EnableScheduling} annotation.
*
* <p>This annotation can be used as a <em>{@linkplain Repeatable repeatable}</em>
* annotation. If several scheduled declarations are found on the same method,
* each of them will be processed independently, with a separate trigger firing
* for each of them. As a consequence, such co-located schedules may overlap
* and execute multiple times in parallel or in immediate succession.
*
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
* <em>composed annotations</em> with attribute overrides.
*
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -160,7 +160,7 @@ public class ScheduledAnnotationBeanPostProcessor
* @since 5.1
*/
public ScheduledAnnotationBeanPostProcessor(ScheduledTaskRegistrar registrar) {
Assert.notNull(registrar, "ScheduledTaskRegistrar must not be null");
Assert.notNull(registrar, "ScheduledTaskRegistrar is required");
this.registrar = registrar;
}
@@ -580,7 +580,7 @@ public class ScheduledAnnotationBeanPostProcessor
}
if (tasks != null) {
for (ScheduledTask task : tasks) {
task.cancel(false);
task.cancel();
}
}
}
@@ -598,7 +598,7 @@ public class ScheduledAnnotationBeanPostProcessor
Collection<Set<ScheduledTask>> allTasks = this.scheduledTasks.values();
for (Set<ScheduledTask> tasks : allTasks) {
for (ScheduledTask task : tasks) {
task.cancel(false);
task.cancel();
}
}
this.scheduledTasks.clear();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -40,10 +40,10 @@ import org.springframework.scheduling.config.ScheduledTaskRegistrar;
public interface SchedulingConfigurer {
/**
* Callback allowing a {@link org.springframework.scheduling.TaskScheduler}
* and specific {@link org.springframework.scheduling.config.Task} instances
* to be registered against the given the {@link ScheduledTaskRegistrar}.
* @param taskRegistrar the registrar to be configured
* Callback allowing a {@link org.springframework.scheduling.TaskScheduler
* TaskScheduler} and specific {@link org.springframework.scheduling.config.Task Task}
* instances to be registered against the given the {@link ScheduledTaskRegistrar}.
* @param taskRegistrar the registrar to be configured.
*/
void configureTasks(ScheduledTaskRegistrar taskRegistrar);
@@ -206,9 +206,9 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
@Override
public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
long delay = startTime.getTime() - this.clock.millis();
long initialDelay = startTime.getTime() - this.clock.millis();
try {
return this.scheduledExecutor.schedule(decorateTask(task, false), delay, TimeUnit.MILLISECONDS);
return this.scheduledExecutor.schedule(decorateTask(task, false), initialDelay, TimeUnit.MILLISECONDS);
}
catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
@@ -108,9 +108,9 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
/**
* Set whether to wait for scheduled tasks to complete on shutdown,
* not interrupting running tasks and executing all tasks in the queue.
* <p>Default is {@code false}, shutting down immediately through interrupting
* ongoing tasks and clearing the queue. Switch this flag to {@code true} if
* you prefer fully completed tasks at the expense of a longer shutdown phase.
* <p>Default is "false", shutting down immediately through interrupting
* ongoing tasks and clearing the queue. Switch this flag to "true" if you
* prefer fully completed tasks at the expense of a longer shutdown phase.
* <p>Note that Spring's container shutdown continues while ongoing tasks
* are being completed. If you want this executor to block and wait for the
* termination of tasks before the rest of the container continues to shut
@@ -211,13 +211,9 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
}
/**
* Perform a full shutdown on the underlying ExecutorService,
* according to the corresponding configuration settings.
* @see #setWaitForTasksToCompleteOnShutdown
* @see #setAwaitTerminationMillis
* Perform a shutdown on the underlying ExecutorService.
* @see java.util.concurrent.ExecutorService#shutdown()
* @see java.util.concurrent.ExecutorService#shutdownNow()
* @see java.util.concurrent.ExecutorService#awaitTermination
*/
public void shutdown() {
if (logger.isDebugEnabled()) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -78,8 +78,8 @@ class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements Sc
if (this.scheduledExecutionTime == null) {
return null;
}
long delay = this.scheduledExecutionTime.getTime() - this.triggerContext.getClock().millis();
this.currentFuture = this.executor.schedule(this, delay, TimeUnit.MILLISECONDS);
long initialDelay = this.scheduledExecutionTime.getTime() - this.triggerContext.getClock().millis();
this.currentFuture = this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS);
return this;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -380,9 +380,9 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
@Override
public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
ScheduledExecutorService executor = getScheduledExecutor();
long delay = startTime.getTime() - this.clock.millis();
long initialDelay = startTime.getTime() - this.clock.millis();
try {
return executor.schedule(errorHandlingTask(task, false), delay, TimeUnit.MILLISECONDS);
return executor.schedule(errorHandlingTask(task, false), initialDelay, TimeUnit.MILLISECONDS);
}
catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -41,8 +41,8 @@ import org.springframework.util.CollectionUtils;
* Helper bean for registering tasks with a {@link TaskScheduler}, typically using cron
* expressions.
*
* <p>{@code ScheduledTaskRegistrar} has a more prominent user-facing role when used in
* conjunction with the {@link
* <p>As of Spring 3.1, {@code ScheduledTaskRegistrar} has a more prominent user-facing
* role when used in conjunction with the {@link
* org.springframework.scheduling.annotation.EnableAsync @EnableAsync} annotation and its
* {@link org.springframework.scheduling.annotation.SchedulingConfigurer
* SchedulingConfigurer} callback interface.
@@ -552,7 +552,7 @@ public class ScheduledTaskRegistrar implements ScheduledTaskHolder, Initializing
@Override
public void destroy() {
for (ScheduledTask task : this.scheduledTasks) {
task.cancel(false);
task.cancel();
}
if (this.localExecutor != null) {
this.localExecutor.shutdownNow();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -102,8 +102,8 @@ public abstract class AbstractBindingResult extends AbstractErrors implements Bi
}
@Override
public void rejectValue(@Nullable String field, String errorCode,
@Nullable Object[] errorArgs, @Nullable String defaultMessage) {
public void rejectValue(@Nullable String field, String errorCode, @Nullable Object[] errorArgs,
@Nullable String defaultMessage) {
if (!StringUtils.hasLength(getNestedPath()) && !StringUtils.hasLength(field)) {
// We're at the top of the nested object hierarchy,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -28,14 +28,13 @@ import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**
* Abstract implementation of the {@link Errors} interface.
* Provides nested path handling but does not define concrete management
* Abstract implementation of the {@link Errors} interface. Provides common
* access to evaluated errors; however, does not define concrete management
* of {@link ObjectError ObjectErrors} and {@link FieldError FieldErrors}.
*
* @author Juergen Hoeller
* @author Rossen Stoyanchev
* @since 2.5.3
* @see AbstractBindingResult
*/
@SuppressWarnings("serial")
public abstract class AbstractErrors implements Errors, Serializable {
@@ -82,8 +81,8 @@ public abstract class AbstractErrors implements Errors, Serializable {
nestedPath = "";
}
nestedPath = canonicalFieldName(nestedPath);
if (nestedPath.length() > 0 && !nestedPath.endsWith(NESTED_PATH_SEPARATOR)) {
nestedPath += NESTED_PATH_SEPARATOR;
if (nestedPath.length() > 0 && !nestedPath.endsWith(Errors.NESTED_PATH_SEPARATOR)) {
nestedPath += Errors.NESTED_PATH_SEPARATOR;
}
this.nestedPath = nestedPath;
}
@@ -98,7 +97,7 @@ public abstract class AbstractErrors implements Errors, Serializable {
}
else {
String path = getNestedPath();
return (path.endsWith(NESTED_PATH_SEPARATOR) ?
return (path.endsWith(Errors.NESTED_PATH_SEPARATOR) ?
path.substring(0, path.length() - NESTED_PATH_SEPARATOR.length()) : path);
}
}
@@ -202,9 +201,9 @@ public abstract class AbstractErrors implements Errors, Serializable {
List<FieldError> fieldErrors = getFieldErrors();
List<FieldError> result = new ArrayList<>();
String fixedField = fixedField(field);
for (FieldError fieldError : fieldErrors) {
if (isMatchingFieldError(fixedField, fieldError)) {
result.add(fieldError);
for (FieldError error : fieldErrors) {
if (isMatchingFieldError(fixedField, error)) {
result.add(error);
}
}
return Collections.unmodifiableList(result);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -55,7 +55,7 @@ public class BeanPropertyBindingResult extends AbstractPropertyBindingResult imp
/**
* Create a new {@code BeanPropertyBindingResult} for the given target.
* Creates a new instance of the {@link BeanPropertyBindingResult} class.
* @param target the target bean to bind onto
* @param objectName the name of the target object
*/
@@ -64,7 +64,7 @@ public class BeanPropertyBindingResult extends AbstractPropertyBindingResult imp
}
/**
* Create a new {@code BeanPropertyBindingResult} for the given target.
* Creates a new instance of the {@link BeanPropertyBindingResult} class.
* @param target the target bean to bind onto
* @param objectName the name of the target object
* @param autoGrowNestedPaths whether to "auto-grow" a nested path that contains a null value
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -128,9 +128,7 @@ public class BindException extends Exception implements BindingResult {
}
@Override
public void rejectValue(@Nullable String field, String errorCode,
@Nullable Object[] errorArgs, @Nullable String defaultMessage) {
public void rejectValue(@Nullable String field, String errorCode, @Nullable Object[] errorArgs, @Nullable String defaultMessage) {
this.bindingResult.rejectValue(field, errorCode, errorArgs, defaultMessage);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -46,7 +46,7 @@ public class DirectFieldBindingResult extends AbstractPropertyBindingResult {
/**
* Create a new {@code DirectFieldBindingResult} for the given target.
* Create a new DirectFieldBindingResult instance.
* @param target the target object to bind onto
* @param objectName the name of the target object
*/
@@ -55,7 +55,7 @@ public class DirectFieldBindingResult extends AbstractPropertyBindingResult {
}
/**
* Create a new {@code DirectFieldBindingResult} for the given target.
* Create a new DirectFieldBindingResult instance.
* @param target the target object to bind onto
* @param objectName the name of the target object
* @param autoGrowNestedPaths whether to "auto-grow" a nested path that contains a null value
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -22,24 +22,24 @@ import org.springframework.beans.PropertyAccessor;
import org.springframework.lang.Nullable;
/**
* Stores and exposes information about data-binding and validation errors
* for a specific object.
* Stores and exposes information about data-binding and validation
* errors for a specific object.
*
* <p>Field names are typically properties of the target object (e.g. "name"
* when binding to a customer object). Implementations may also support nested
* fields in case of nested objects (e.g. "address.street"), in conjunction
* with subtree navigation via {@link #setNestedPath}: for example, an
* {@code AddressValidator} may validate "address", not being aware that this
* is a nested object of a top-level customer object.
* <p>Field names can be properties of the target object (e.g. "name"
* when binding to a customer object), or nested fields in case of
* subobjects (e.g. "address.street"). Supports subtree navigation
* via {@link #setNestedPath(String)}: for example, an
* {@code AddressValidator} validates "address", not being aware
* that this is a subobject of customer.
*
* <p>Note: {@code Errors} objects are single-threaded.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see Validator
* @see ValidationUtils
* @see #setNestedPath
* @see BindException
* @see BindingResult
* @see DataBinder
* @see ValidationUtils
*/
public interface Errors {
@@ -66,7 +66,6 @@ public interface Errors {
* @param nestedPath nested path within this object,
* e.g. "address" (defaults to "", {@code null} is also acceptable).
* Can end with a dot: both "address" and "address." are valid.
* @see #getNestedPath()
*/
void setNestedPath(String nestedPath);
@@ -74,7 +73,6 @@ public interface Errors {
* Return the current nested path of this {@link Errors} object.
* <p>Returns a nested path with a dot, i.e. "address.", for easy
* building of concatenated paths. Default is an empty String.
* @see #setNestedPath(String)
*/
String getNestedPath();
@@ -88,14 +86,14 @@ public interface Errors {
* <p>For example: current path "spouse.", pushNestedPath("child") &rarr;
* result path "spouse.child."; popNestedPath() &rarr; "spouse." again.
* @param subPath the sub path to push onto the nested path stack
* @see #popNestedPath()
* @see #popNestedPath
*/
void pushNestedPath(String subPath);
/**
* Pop the former nested path from the nested path stack.
* @throws IllegalStateException if there is no former nested path on the stack
* @see #pushNestedPath(String)
* @see #pushNestedPath
*/
void popNestedPath() throws IllegalStateException;
@@ -103,7 +101,6 @@ public interface Errors {
* Register a global error for the entire target object,
* using the given error description.
* @param errorCode error code, interpretable as a message key
* @see #reject(String, Object[], String)
*/
void reject(String errorCode);
@@ -112,7 +109,6 @@ public interface Errors {
* using the given error description.
* @param errorCode error code, interpretable as a message key
* @param defaultMessage fallback default message
* @see #reject(String, Object[], String)
*/
void reject(String errorCode, String defaultMessage);
@@ -123,7 +119,6 @@ public interface Errors {
* @param errorArgs error arguments, for argument binding via MessageFormat
* (can be {@code null})
* @param defaultMessage fallback default message
* @see #rejectValue(String, String, Object[], String)
*/
void reject(String errorCode, @Nullable Object[] errorArgs, @Nullable String defaultMessage);
@@ -137,7 +132,7 @@ public interface Errors {
* global error if the current object is the top object.
* @param field the field name (may be {@code null} or empty String)
* @param errorCode error code, interpretable as a message key
* @see #rejectValue(String, String, Object[], String)
* @see #getNestedPath()
*/
void rejectValue(@Nullable String field, String errorCode);
@@ -152,7 +147,7 @@ public interface Errors {
* @param field the field name (may be {@code null} or empty String)
* @param errorCode error code, interpretable as a message key
* @param defaultMessage fallback default message
* @see #rejectValue(String, String, Object[], String)
* @see #getNestedPath()
*/
void rejectValue(@Nullable String field, String errorCode, String defaultMessage);
@@ -169,7 +164,7 @@ public interface Errors {
* @param errorArgs error arguments, for argument binding via MessageFormat
* (can be {@code null})
* @param defaultMessage fallback default message
* @see #reject(String, Object[], String)
* @see #getNestedPath()
*/
void rejectValue(@Nullable String field, String errorCode,
@Nullable Object[] errorArgs, @Nullable String defaultMessage);
@@ -184,40 +179,35 @@ public interface Errors {
* to refer to the same target object, or at least contain compatible errors
* that apply to the target object of this {@code Errors} instance.
* @param errors the {@code Errors} instance to merge in
* @see #getAllErrors()
*/
void addAllErrors(Errors errors);
/**
* Determine if there were any errors.
* @see #hasGlobalErrors()
* @see #hasFieldErrors()
* Return if there were any errors.
*/
boolean hasErrors();
/**
* Determine the total number of errors.
* @see #getGlobalErrorCount()
* @see #getFieldErrorCount()
* Return the total number of errors.
*/
int getErrorCount();
/**
* Get all errors, both global and field ones.
* @return a list of {@link ObjectError}/{@link FieldError} instances
* @see #getGlobalErrors()
* @see #getFieldErrors()
* @return a list of {@link ObjectError} instances
*/
List<ObjectError> getAllErrors();
/**
* Determine if there were any global errors.
* Are there any global errors?
* @return {@code true} if there are any global errors
* @see #hasFieldErrors()
*/
boolean hasGlobalErrors();
/**
* Determine the number of global errors.
* Return the number of global errors.
* @return the number of global errors
* @see #getFieldErrorCount()
*/
int getGlobalErrorCount();
@@ -225,26 +215,26 @@ public interface Errors {
/**
* Get all global errors.
* @return a list of {@link ObjectError} instances
* @see #getFieldErrors()
*/
List<ObjectError> getGlobalErrors();
/**
* Get the <i>first</i> global error, if any.
* @return the global error, or {@code null}
* @see #getFieldError()
*/
@Nullable
ObjectError getGlobalError();
/**
* Determine if there were any errors associated with a field.
* Are there any field errors?
* @return {@code true} if there are any errors associated with a field
* @see #hasGlobalErrors()
*/
boolean hasFieldErrors();
/**
* Determine the number of errors associated with a field.
* Return the number of errors associated with a field.
* @return the number of errors associated with a field
* @see #getGlobalErrorCount()
*/
int getFieldErrorCount();
@@ -252,39 +242,36 @@ public interface Errors {
/**
* Get all errors associated with a field.
* @return a List of {@link FieldError} instances
* @see #getGlobalErrors()
*/
List<FieldError> getFieldErrors();
/**
* Get the <i>first</i> error associated with a field, if any.
* @return the field-specific error, or {@code null}
* @see #getGlobalError()
*/
@Nullable
FieldError getFieldError();
/**
* Determine if there were any errors associated with the given field.
* Are there any errors associated with the given field?
* @param field the field name
* @see #hasFieldErrors()
* @return {@code true} if there were any errors associated with the given field
*/
boolean hasFieldErrors(String field);
/**
* Determine the number of errors associated with the given field.
* Return the number of errors associated with the given field.
* @param field the field name
* @see #getFieldErrorCount()
* @return the number of errors associated with the given field
*/
int getFieldErrorCount(String field);
/**
* Get all errors associated with the given field.
* <p>Implementations may support not only full field names like
* "address.street" but also pattern matches like "address.*".
* <p>Implementations should support not only full field names like
* "name" but also pattern matches like "na*" or "address.*".
* @param field the field name
* @return a List of {@link FieldError} instances
* @see #getFieldErrors()
*/
List<FieldError> getFieldErrors(String field);
@@ -292,7 +279,6 @@ public interface Errors {
* Get the first error associated with the given field, if any.
* @param field the field name
* @return the field-specific error, or {@code null}
* @see #getFieldError()
*/
@Nullable
FieldError getFieldError(String field);
@@ -304,19 +290,17 @@ public interface Errors {
* even if there were type mismatches.
* @param field the field name
* @return the current value of the given field
* @see #getFieldType(String)
*/
@Nullable
Object getFieldValue(String field);
/**
* Determine the type of the given field, as far as possible.
* Return the type of a given field.
* <p>Implementations should be able to determine the type even
* when the field value is {@code null}, for example from some
* associated descriptor.
* @param field the field name
* @return the type of the field, or {@code null} if not determinable
* @see #getFieldValue(String)
*/
@Nullable
Class<?> getFieldType(String field);
@@ -124,10 +124,8 @@ public class FieldError extends ObjectError {
@Override
public String toString() {
// We would preferably use ObjectUtils.nullSafeConciseToString(rejectedValue) here but
// keep including the full nullSafeToString representation for backwards compatibility.
return "Field error in object '" + getObjectName() + "' on field '" + this.field +
"': rejected value [" + ObjectUtils.nullSafeToString(this.rejectedValue) + "]; " +
"': rejected value [" + ObjectUtils.nullSafeConciseToString(this.rejectedValue) + "]; " +
resolvableToString();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -54,14 +54,14 @@ package org.springframework.validation;
* }
* }</pre>
*
* <p>See also the Spring reference manual for a fuller discussion of the
* {@code Validator} interface and its role in an enterprise application.
* <p>See also the Spring reference manual for a fuller discussion of
* the {@code Validator} interface and its role in an enterprise
* application.
*
* @author Rod Johnson
* @see SmartValidator
* @see Errors
* @see ValidationUtils
* @see DataBinder#setValidator
*/
public interface Validator {
@@ -81,14 +81,11 @@ public interface Validator {
boolean supports(Class<?> clazz);
/**
* Validate the given {@code target} object which must be of a
* {@link Class} for which the {@link #supports(Class)} method
* typically has returned (or would return) {@code true}.
* Validate the supplied {@code target} object, which must be
* of a {@link Class} for which the {@link #supports(Class)} method
* typically has (or would) return {@code true}.
* <p>The supplied {@link Errors errors} instance can be used to report
* any resulting validation errors, typically as part of a larger
* binding process which this validator is meant to participate in.
* Binding errors have typically been pre-registered with the
* {@link Errors errors} instance before this invocation already.
* any resulting validation errors.
* @param target the object that is to be validated
* @param errors contextual state about the validation process
* @see ValidationUtils
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -26,46 +26,37 @@ import org.springframework.lang.Nullable;
* Mainly for internal use within the framework.
*
* @author Christoph Dreis
* @author Juergen Hoeller
* @since 5.3.7
*/
public abstract class ValidationAnnotationUtils {
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
/**
* Determine any validation hints by the given annotation.
* <p>This implementation checks for Spring's
* {@link org.springframework.validation.annotation.Validated},
* {@code @javax.validation.Valid}, and custom annotations whose
* name starts with "Valid" which may optionally declare validation
* hints through the "value" attribute.
* <p>This implementation checks for {@code @javax.validation.Valid},
* Spring's {@link org.springframework.validation.annotation.Validated},
* and custom annotations whose name starts with "Valid".
* @param ann the annotation (potentially a validation annotation)
* @return the validation hints to apply (possibly an empty array),
* or {@code null} if this annotation does not trigger any validation
*/
@Nullable
public static Object[] determineValidationHints(Annotation ann) {
// Direct presence of @Validated ?
if (ann instanceof Validated) {
return ((Validated) ann).value();
}
// Direct presence of @Valid ?
Class<? extends Annotation> annotationType = ann.annotationType();
if ("javax.validation.Valid".equals(annotationType.getName())) {
String annotationName = annotationType.getName();
if ("javax.validation.Valid".equals(annotationName)) {
return EMPTY_OBJECT_ARRAY;
}
// Meta presence of @Validated ?
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
if (validatedAnn != null) {
return validatedAnn.value();
Object hints = validatedAnn.value();
return convertValidationHints(hints);
}
// Custom validation annotation ?
if (annotationType.getSimpleName().startsWith("Valid")) {
return convertValidationHints(AnnotationUtils.getValue(ann));
Object hints = AnnotationUtils.getValue(ann);
return convertValidationHints(hints);
}
// No validation triggered
return null;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -108,7 +108,7 @@ open class BeanDefinitionDsl internal constructor (private val init: BeanDefinit
SINGLETON,
/**
* Scope constant for the standard prototype scope
* Scope constant for the standard singleton scope
* @see org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE
*/
PROTOTYPE
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -118,7 +118,6 @@ class CacheReproTests {
assertThat(cacheResolver.getCache("foo").get("foo")).isNull();
Object result = bean.getSimple("foo"); // cache name = id
assertThat(cacheResolver.getCache("foo").get("foo").get()).isEqualTo(result);
context.close();
}
@@ -128,7 +127,7 @@ class CacheReproTests {
Spr13081Service bean = context.getBean(Spr13081Service.class);
assertThatIllegalStateException().isThrownBy(() -> bean.getSimple(null))
.withMessageContaining(MyCacheResolver.class.getName());
.withMessageContaining(MyCacheResolver.class.getName());
context.close();
}
@@ -147,7 +146,6 @@ class CacheReproTests {
TestBean tb2 = bean.findById("tb1").get();
assertThat(tb2).isNotSameAs(tb);
assertThat(cache.get("tb1").get()).isSameAs(tb2);
context.close();
}
@@ -179,7 +177,6 @@ class CacheReproTests {
bean.insertItem(tb);
assertThat(bean.findById("tb1").get()).isSameAs(tb);
assertThat(cache.get("tb1").get()).isSameAs(tb);
context.close();
}
@@ -193,7 +190,6 @@ class CacheReproTests {
bean.insertItem(tb);
assertThat(bean.findById("tb1").get()).isSameAs(tb);
assertThat(cache.get("tb1").get()).isSameAs(tb);
context.close();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -48,9 +48,8 @@ public class CacheSyncFailureTests {
private SimpleService simpleService;
@BeforeEach
public void setup() {
public void setUp() {
this.context = new AnnotationConfigApplicationContext(Config.class);
this.simpleService = this.context.getBean(SimpleService.class);
}
@@ -62,40 +61,39 @@ public class CacheSyncFailureTests {
}
}
@Test
public void unlessSync() {
assertThatIllegalStateException()
.isThrownBy(() -> this.simpleService.unlessSync("key"))
.withMessageContaining("A sync=true operation does not support the unless attribute");
assertThatIllegalStateException().isThrownBy(() ->
this.simpleService.unlessSync("key"))
.withMessageContaining("@Cacheable(sync=true) does not support unless attribute");
}
@Test
public void severalCachesSync() {
assertThatIllegalStateException()
.isThrownBy(() -> this.simpleService.severalCachesSync("key"))
.withMessageContaining("A sync=true operation is restricted to a single cache");
assertThatIllegalStateException().isThrownBy(() ->
this.simpleService.severalCachesSync("key"))
.withMessageContaining("@Cacheable(sync=true) only allows a single cache");
}
@Test
public void severalCachesWithResolvedSync() {
assertThatIllegalStateException()
.isThrownBy(() -> this.simpleService.severalCachesWithResolvedSync("key"))
.withMessageContaining("A sync=true operation is restricted to a single cache");
assertThatIllegalStateException().isThrownBy(() ->
this.simpleService.severalCachesWithResolvedSync("key"))
.withMessageContaining("@Cacheable(sync=true) only allows a single cache");
}
@Test
public void syncWithAnotherOperation() {
assertThatIllegalStateException()
.isThrownBy(() -> this.simpleService.syncWithAnotherOperation("key"))
.withMessageContaining("A sync=true operation cannot be combined with other cache operations");
assertThatIllegalStateException().isThrownBy(() ->
this.simpleService.syncWithAnotherOperation("key"))
.withMessageContaining("@Cacheable(sync=true) cannot be combined with other cache operations");
}
@Test
public void syncWithTwoGetOperations() {
assertThatIllegalStateException()
.isThrownBy(() -> this.simpleService.syncWithTwoGetOperations("key"))
.withMessageContaining("Only one sync=true operation is allowed");
assertThatIllegalStateException().isThrownBy(() ->
this.simpleService.syncWithTwoGetOperations("key"))
.withMessageContaining("Only one @Cacheable(sync=true) entry is allowed");
}
@@ -133,7 +131,6 @@ public class CacheSyncFailureTests {
}
}
@Configuration
@EnableCaching
static class Config implements CachingConfigurer {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -197,7 +197,6 @@ public class ClassPathBeanDefinitionScannerTests {
context.registerBeanDefinition("stubFooDao", new RootBeanDefinition(TestBean.class));
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.setIncludeAnnotationConfig(false);
// should not fail!
scanner.scan(BASE_PACKAGE);
}
@@ -208,10 +207,10 @@ public class ClassPathBeanDefinitionScannerTests {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.setIncludeAnnotationConfig(false);
scanner.scan("org.springframework.context.annotation3");
assertThatIllegalStateException().isThrownBy(() -> scanner.scan(BASE_PACKAGE))
.withMessageContaining("stubFooDao")
.withMessageContaining(StubFooDao.class.getName());
assertThatIllegalStateException().isThrownBy(() ->
scanner.scan(BASE_PACKAGE))
.withMessageContaining("stubFooDao")
.withMessageContaining(StubFooDao.class.getName());
}
@Test
@@ -268,10 +267,11 @@ public class ClassPathBeanDefinitionScannerTests {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.setIncludeAnnotationConfig(false);
scanner.scan("org.springframework.context.annotation2");
assertThatIllegalStateException().isThrownBy(() -> scanner.scan(BASE_PACKAGE))
.withMessageContaining("myNamedDao")
.withMessageContaining(NamedStubDao.class.getName())
.withMessageContaining(NamedStubDao2.class.getName());
assertThatIllegalStateException().isThrownBy(() ->
scanner.scan(BASE_PACKAGE))
.withMessageContaining("myNamedDao")
.withMessageContaining(NamedStubDao.class.getName())
.withMessageContaining(NamedStubDao2.class.getName());
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -79,7 +79,7 @@ class EnableLoadTimeWeavingTests {
@Configuration
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.DISABLED)
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.DISABLED)
static class EnableLTWConfig_withAjWeavingDisabled implements LoadTimeWeavingConfigurer {
@Override
@@ -88,9 +88,8 @@ class EnableLoadTimeWeavingTests {
}
}
@Configuration
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.AUTODETECT)
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.AUTODETECT)
static class EnableLTWConfig_withAjWeavingAutodetect implements LoadTimeWeavingConfigurer {
@Override
@@ -99,9 +98,8 @@ class EnableLoadTimeWeavingTests {
}
}
@Configuration
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.ENABLED)
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
static class EnableLTWConfig_withAjWeavingEnabled implements LoadTimeWeavingConfigurer {
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -164,12 +164,12 @@ class AnnotationDrivenEventListenerTests {
ContextEventListener listener = this.context.getBean(ContextEventListener.class);
List<Object> events = this.eventCollector.getEvents(listener);
assertThat(events).as("Wrong number of initial context events").hasSize(1);
assertThat(events.size()).as("Wrong number of initial context events").isEqualTo(1);
assertThat(events.get(0).getClass()).isEqualTo(ContextRefreshedEvent.class);
this.context.stop();
List<Object> eventsAfterStop = this.eventCollector.getEvents(listener);
assertThat(eventsAfterStop).as("Wrong number of context events on shutdown").hasSize(2);
assertThat(eventsAfterStop.size()).as("Wrong number of context events on shutdown").isEqualTo(2);
assertThat(eventsAfterStop.get(1).getClass()).isEqualTo(ContextStoppedEvent.class);
this.eventCollector.assertTotalEventsCount(2);
}
@@ -334,7 +334,7 @@ class AnnotationDrivenEventListenerTests {
load(ScopedProxyTestBean.class);
SimpleService proxy = this.context.getBean(SimpleService.class);
assertThat(proxy).as("bean should be a proxy").isInstanceOf(Advised.class);
assertThat(proxy instanceof Advised).as("bean should be a proxy").isTrue();
this.eventCollector.assertNoEventReceived(proxy.getId());
this.context.publishEvent(new ContextRefreshedEvent(this.context));
@@ -351,7 +351,7 @@ class AnnotationDrivenEventListenerTests {
load(AnnotatedProxyTestBean.class);
AnnotatedSimpleService proxy = this.context.getBean(AnnotatedSimpleService.class);
assertThat(proxy).as("bean should be a proxy").isInstanceOf(Advised.class);
assertThat(proxy instanceof Advised).as("bean should be a proxy").isTrue();
this.eventCollector.assertNoEventReceived(proxy.getId());
this.context.publishEvent(new ContextRefreshedEvent(this.context));
@@ -517,6 +517,7 @@ class AnnotationDrivenEventListenerTests {
ReplyEventListener replyEventListener = this.context.getBean(ReplyEventListener.class);
TestEventListener listener = this.context.getBean(TestEventListener.class);
this.eventCollector.assertNoEventReceived(listener);
this.eventCollector.assertNoEventReceived(replyEventListener);
this.context.publishEvent(event);
@@ -633,17 +634,6 @@ class AnnotationDrivenEventListenerTests {
assertThat(listener.order).contains("first", "second", "third");
}
@Test
void publicSubclassWithInheritedEventListener() {
load(PublicSubclassWithInheritedEventListener.class);
TestEventListener listener = this.context.getBean(PublicSubclassWithInheritedEventListener.class);
this.eventCollector.assertNoEventReceived(listener);
this.context.publishEvent("test");
this.eventCollector.assertEvent(listener, "test");
this.eventCollector.assertTotalEventsCount(1);
}
@Test @Disabled // SPR-15122
void listenersReceiveEarlyEvents() {
load(EventOnPostConstruct.class, OrderedTestListener.class);
@@ -656,7 +646,7 @@ class AnnotationDrivenEventListenerTests {
void missingListenerBeanIgnored() {
load(MissingEventListener.class);
context.getBean(UseMissingEventListener.class);
context.publishEvent(new TestEvent(this));
context.getBean(ApplicationEventMulticaster.class).multicastEvent(new TestEvent(this));
}
@@ -763,6 +753,7 @@ class AnnotationDrivenEventListenerTests {
public void handleContextEvent(ApplicationContextEvent event) {
collectEvent(event);
}
}
@@ -989,6 +980,7 @@ class AnnotationDrivenEventListenerTests {
}
@EventListener
@Retention(RetentionPolicy.RUNTIME)
public @interface ConditionalEvent {
@@ -1040,7 +1032,7 @@ class AnnotationDrivenEventListenerTests {
}
@Component
@Configuration
static class OrderedTestListener extends TestEventListener {
public final List<String> order = new ArrayList<>();
@@ -1064,11 +1056,6 @@ class AnnotationDrivenEventListenerTests {
}
@Component
public static class PublicSubclassWithInheritedEventListener extends TestEventListener {
}
static class EventOnPostConstruct {
@Autowired
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@ package org.springframework.context.event;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.List;
import org.junit.jupiter.api.Test;
@@ -47,8 +46,6 @@ import static org.mockito.Mockito.verify;
/**
* @author Stephane Nicoll
* @author Juergen Hoeller
* @author Simon Baslé
*/
public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEventListenerTests {
@@ -83,23 +80,16 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv
supportsEventType(false, method, ResolvableType.forClassWithGenerics(GenericTestEvent.class, Long.class));
}
@Test
public void genericListenerWithUnresolvedGenerics() {
Method method = ReflectionUtils.findMethod(
SampleEvents.class, "handleGenericString", GenericTestEvent.class);
supportsEventType(true, method, ResolvableType.forClass(GenericTestEvent.class));
}
@Test
public void listenerWithPayloadAndGenericInformation() {
Method method = ReflectionUtils.findMethod(SampleEvents.class, "handleString", String.class);
supportsEventType(true, method, createPayloadEventType(String.class));
supportsEventType(true, method, createGenericEventType(String.class));
}
@Test
public void listenerWithInvalidPayloadAndGenericInformation() {
Method method = ReflectionUtils.findMethod(SampleEvents.class, "handleString", String.class);
supportsEventType(false, method, createPayloadEventType(Integer.class));
supportsEventType(false, method, createGenericEventType(Integer.class));
}
@Test
@@ -123,28 +113,28 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv
@Test
public void listenerWithAnnotationValue() {
Method method = ReflectionUtils.findMethod(SampleEvents.class, "handleStringAnnotationValue");
supportsEventType(true, method, createPayloadEventType(String.class));
supportsEventType(true, method, createGenericEventType(String.class));
}
@Test
public void listenerWithAnnotationClasses() {
Method method = ReflectionUtils.findMethod(SampleEvents.class, "handleStringAnnotationClasses");
supportsEventType(true, method, createPayloadEventType(String.class));
supportsEventType(true, method, createGenericEventType(String.class));
}
@Test
public void listenerWithAnnotationValueAndParameter() {
Method method = ReflectionUtils.findMethod(
SampleEvents.class, "handleStringAnnotationValueAndParameter", String.class);
supportsEventType(true, method, createPayloadEventType(String.class));
supportsEventType(true, method, createGenericEventType(String.class));
}
@Test
public void listenerWithSeveralTypes() {
Method method = ReflectionUtils.findMethod(SampleEvents.class, "handleStringOrInteger");
supportsEventType(true, method, createPayloadEventType(String.class));
supportsEventType(true, method, createPayloadEventType(Integer.class));
supportsEventType(false, method, createPayloadEventType(Double.class));
supportsEventType(true, method, createGenericEventType(String.class));
supportsEventType(true, method, createGenericEventType(Integer.class));
supportsEventType(false, method, createGenericEventType(Double.class));
}
@Test
@@ -335,88 +325,6 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv
verify(this.context, times(2)).getBean("testBean");
}
@Test // gh-30399
void simplePayloadDoesNotSupportArbitraryGenericEventType() throws Exception {
Method method = SampleEvents.class.getDeclaredMethod("handleString", String.class);
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClassWithGenerics(EntityWrapper.class, Integer.class))))
.as("handleString(String) with EntityWrapper<Integer>").isFalse();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClass(EntityWrapper.class))))
.as("handleString(String) with EntityWrapper<?>").isFalse();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClass(String.class))))
.as("handleString(String) with String").isTrue();
}
@Test // gh-30399
void genericPayloadDoesNotSupportArbitraryGenericEventType() throws Exception {
Method method = SampleEvents.class.getDeclaredMethod("handleGenericStringPayload", EntityWrapper.class);
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClass(EntityWrapper.class))))
.as("handleGenericStringPayload(EntityWrapper<String>) with EntityWrapper<?>").isFalse();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClassWithGenerics(EntityWrapper.class, Integer.class))))
.as("handleGenericStringPayload(EntityWrapper<String>) with EntityWrapper<Integer>").isFalse();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClassWithGenerics(EntityWrapper.class, String.class))))
.as("handleGenericStringPayload(EntityWrapper<String>) with EntityWrapper<String>").isTrue();
}
@Test // gh-30399
void rawGenericPayloadDoesNotSupportArbitraryGenericEventType() throws Exception {
Method method = SampleEvents.class.getDeclaredMethod("handleGenericAnyPayload", EntityWrapper.class);
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClass(EntityWrapper.class))))
.as("handleGenericAnyPayload(EntityWrapper<?>) with EntityWrapper<?>").isTrue();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClassWithGenerics(EntityWrapper.class, Integer.class))))
.as("handleGenericAnyPayload(EntityWrapper<?>) with EntityWrapper<Integer>").isTrue();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClassWithGenerics(EntityWrapper.class, String.class))))
.as("handleGenericAnyPayload(EntityWrapper<?>) with EntityWrapper<String>").isTrue();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClass(List.class))))
.as("handleGenericAnyPayload(EntityWrapper<?>) with List<?>").isFalse();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClassWithGenerics(List.class, String.class))))
.as("handleGenericAnyPayload(EntityWrapper<?>) with List<String>").isFalse();
}
@Test // gh-30399
void genericApplicationEventSupportsSpecificType() throws Exception {
Method method = SampleEvents.class.getDeclaredMethod("handleGenericString", GenericTestEvent.class);
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
assertThat(adapter.supportsEventType(ResolvableType.forClass(GenericTestEvent.class)))
.as("handleGenericString(GenericTestEvent<String>) with GenericTestEvent<?>").isTrue();
assertThat(adapter.supportsEventType(ResolvableType.forClassWithGenerics(GenericTestEvent.class, Integer.class)))
.as("handleGenericString(GenericTestEvent<String>) with GenericTestEvent<Integer>").isFalse();
assertThat(adapter.supportsEventType(ResolvableType.forClassWithGenerics(GenericTestEvent.class, String.class)))
.as("handleGenericString(GenericTestEvent<String>) with GenericTestEvent<String>").isTrue();
}
@Test // gh-30399
void genericRawApplicationEventSupportsRawTypeAndAnySpecificType() throws Exception {
Method method = SampleEvents.class.getDeclaredMethod("handleGenericRaw", GenericTestEvent.class);
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
assertThat(adapter.supportsEventType(ResolvableType.forClass(GenericTestEvent.class)))
.as("handleGenericRaw(GenericTestEvent<?>) with GenericTestEvent<?>").isTrue();
assertThat(adapter.supportsEventType(ResolvableType.forClassWithGenerics(GenericTestEvent.class, String.class)))
.as("handleGenericRaw(GenericTestEvent<?>) with GenericTestEvent<String>").isTrue();
assertThat(adapter.supportsEventType(ResolvableType.forClassWithGenerics(GenericTestEvent.class, Integer.class)))
.as("handleGenericRaw(GenericTestEvent<?>) with GenericTestEvent<Integer>").isTrue();
}
@Test // gh-30399
void unrelatedApplicationEventDoesNotSupportRawTypeOrAnySpecificType() throws Exception {
Method method = SampleEvents.class.getDeclaredMethod("handleUnrelated", ContextRefreshedEvent.class);
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
assertThat(adapter.supportsEventType(ResolvableType.forClass(GenericTestEvent.class)))
.as("handleUnrelated(ContextRefreshedEvent) with GenericTestEvent<?>").isTrue(); // known bug in 5.3.x
assertThat(adapter.supportsEventType(ResolvableType.forClassWithGenerics(GenericTestEvent.class, String.class)))
.as("handleUnrelated(ContextRefreshedEvent) with GenericTestEvent<String>").isFalse();
assertThat(adapter.supportsEventType(ResolvableType.forClassWithGenerics(GenericTestEvent.class, Integer.class)))
.as("handleUnrelated(ContextRefreshedEvent) with GenericTestEvent<Integer>").isFalse();
}
private void supportsEventType(boolean match, Method method, ResolvableType eventType) {
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
@@ -433,11 +341,7 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv
return new StaticApplicationListenerMethodAdapter(method, this.sampleEvents);
}
private ResolvableType createPayloadEventType(Class<?> payloadType) {
return ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, payloadType);
}
private ResolvableType createPayloadEventType(ResolvableType payloadType) {
private ResolvableType createGenericEventType(Class<?> payloadType) {
return ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, payloadType);
}
@@ -469,14 +373,6 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv
public void handleGenericString(GenericTestEvent<String> event) {
}
@EventListener
public void handleGenericRaw(GenericTestEvent<?> event) {
}
@EventListener
public void handleUnrelated(ContextRefreshedEvent event) {
}
@EventListener
public void handleString(String payload) {
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -85,13 +85,16 @@ public class ReflectiveLoadTimeWeaverTests {
private int numTimesAddTransformerCalled = 0;
public int getNumTimesGetThrowawayClassLoaderCalled() {
return this.numTimesAddTransformerCalled;
}
public void addTransformer(ClassFileTransformer transformer) {
++this.numTimesAddTransformerCalled;
}
}
@@ -99,15 +102,18 @@ public class ReflectiveLoadTimeWeaverTests {
private int numTimesGetThrowawayClassLoaderCalled = 0;
@Override
public int getNumTimesGetThrowawayClassLoaderCalled() {
return this.numTimesGetThrowawayClassLoaderCalled;
}
public ClassLoader getThrowawayClassLoader() {
++this.numTimesGetThrowawayClassLoaderCalled;
return getClass().getClassLoader();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -95,8 +95,9 @@ public class EnableAsyncTests {
public void properExceptionForExistingProxyDependencyMismatch() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AsyncConfig.class, AsyncBeanWithInterface.class, AsyncBeanUser.class);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(ctx::refresh)
.withCauseInstanceOf(BeanNotOfRequiredTypeException.class);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
ctx::refresh)
.withCauseInstanceOf(BeanNotOfRequiredTypeException.class);
ctx.close();
}
@@ -104,8 +105,9 @@ public class EnableAsyncTests {
public void properExceptionForResolvedProxyDependencyMismatch() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AsyncConfig.class, AsyncBeanUser.class, AsyncBeanWithInterface.class);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(ctx::refresh)
.withCauseInstanceOf(BeanNotOfRequiredTypeException.class);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
ctx::refresh)
.withCauseInstanceOf(BeanNotOfRequiredTypeException.class);
ctx.close();
}
@@ -180,7 +182,8 @@ public class EnableAsyncTests {
@SuppressWarnings("resource")
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AspectJAsyncAnnotationConfig.class);
assertThatExceptionOfType(BeanDefinitionStoreException.class).isThrownBy(ctx::refresh);
assertThatExceptionOfType(BeanDefinitionStoreException.class).isThrownBy(
ctx::refresh);
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -61,9 +61,9 @@ public class EnableSchedulingTests {
@EnabledForTestGroups(LONG_RUNNING)
public void withFixedRateTask() throws InterruptedException {
ctx = new AnnotationConfigApplicationContext(FixedRateTaskConfig.class);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(2);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks().size()).isEqualTo(2);
Thread.sleep(110);
Thread.sleep(100);
assertThat(ctx.getBean(AtomicInteger.class).get()).isGreaterThanOrEqualTo(10);
}
@@ -71,9 +71,9 @@ public class EnableSchedulingTests {
@EnabledForTestGroups(LONG_RUNNING)
public void withSubclass() throws InterruptedException {
ctx = new AnnotationConfigApplicationContext(FixedRateTaskConfigSubclass.class);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(2);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks().size()).isEqualTo(2);
Thread.sleep(110);
Thread.sleep(100);
assertThat(ctx.getBean(AtomicInteger.class).get()).isGreaterThanOrEqualTo(10);
}
@@ -81,13 +81,13 @@ public class EnableSchedulingTests {
@EnabledForTestGroups(LONG_RUNNING)
public void withExplicitScheduler() throws InterruptedException {
ctx = new AnnotationConfigApplicationContext(ExplicitSchedulerConfig.class);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(1);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks().size()).isEqualTo(1);
Thread.sleep(110);
Thread.sleep(100);
assertThat(ctx.getBean(AtomicInteger.class).get()).isGreaterThanOrEqualTo(10);
assertThat(ctx.getBean(ExplicitSchedulerConfig.class).threadName).startsWith("explicitScheduler-");
assertThat(Arrays.asList(ctx.getDefaultListableBeanFactory().getDependentBeans("myTaskScheduler")).contains(
TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)).isTrue();
TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)).isTrue();
}
@Test
@@ -100,9 +100,9 @@ public class EnableSchedulingTests {
@EnabledForTestGroups(LONG_RUNNING)
public void withExplicitScheduledTaskRegistrar() throws InterruptedException {
ctx = new AnnotationConfigApplicationContext(ExplicitScheduledTaskRegistrarConfig.class);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(1);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks().size()).isEqualTo(1);
Thread.sleep(110);
Thread.sleep(100);
assertThat(ctx.getBean(AtomicInteger.class).get()).isGreaterThanOrEqualTo(10);
assertThat(ctx.getBean(ExplicitScheduledTaskRegistrarConfig.class).threadName).startsWith("explicitScheduler1");
}
@@ -124,7 +124,7 @@ public class EnableSchedulingTests {
ctx = new AnnotationConfigApplicationContext(
SchedulingEnabled_withAmbiguousTaskSchedulers_andSingleTask_disambiguatedByScheduledTaskRegistrar.class);
Thread.sleep(110);
Thread.sleep(100);
assertThat(ctx.getBean(ThreadAwareWorker.class).executedByThread).startsWith("explicitScheduler2-");
}
@@ -134,7 +134,7 @@ public class EnableSchedulingTests {
ctx = new AnnotationConfigApplicationContext(
SchedulingEnabled_withAmbiguousTaskSchedulers_andSingleTask_disambiguatedBySchedulerNameAttribute.class);
Thread.sleep(110);
Thread.sleep(100);
assertThat(ctx.getBean(ThreadAwareWorker.class).executedByThread).startsWith("explicitScheduler2-");
}
@@ -143,7 +143,7 @@ public class EnableSchedulingTests {
public void withTaskAddedVia_configureTasks() throws InterruptedException {
ctx = new AnnotationConfigApplicationContext(SchedulingEnabled_withTaskAddedVia_configureTasks.class);
Thread.sleep(110);
Thread.sleep(100);
assertThat(ctx.getBean(ThreadAwareWorker.class).executedByThread).startsWith("taskScheduler-");
}
@@ -152,7 +152,7 @@ public class EnableSchedulingTests {
public void withTriggerTask() throws InterruptedException {
ctx = new AnnotationConfigApplicationContext(TriggerTaskConfig.class);
Thread.sleep(110);
Thread.sleep(100);
assertThat(ctx.getBean(AtomicInteger.class).get()).isGreaterThan(1);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -55,7 +55,7 @@ abstract class AbstractSchedulingTaskExecutorTests {
@BeforeEach
void setup(TestInfo testInfo) {
void setUp(TestInfo testInfo) {
this.testName = testInfo.getTestMethod().get().getName();
this.threadNamePrefix = this.testName + "-";
this.executor = buildExecutor();
@@ -84,11 +84,11 @@ abstract class AbstractSchedulingTaskExecutorTests {
TestTask task = new TestTask(this.testName, 0);
executor.execute(task);
Awaitility.await()
.dontCatchUncaughtExceptions()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> task.exception.get() != null && task.exception.get().getMessage().equals(
"TestTask failure for test 'executeFailingRunnable': expectedRunCount:<0>, actualRunCount:<1>"));
.dontCatchUncaughtExceptions()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> task.exception.get() != null && task.exception.get().getMessage().equals(
"TestTask failure for test 'executeFailingRunnable': expectedRunCount:<0>, actualRunCount:<1>"));
}
@Test
@@ -101,7 +101,7 @@ abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
void submitFailingRunnable() {
void submitFailingRunnable() throws Exception {
TestTask task = new TestTask(this.testName, 0);
Future<?> future = executor.submit(task);
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() ->
@@ -121,31 +121,31 @@ abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
void submitListenableRunnable() {
void submitListenableRunnable() throws Exception {
TestTask task = new TestTask(this.testName, 1);
// Act
ListenableFuture<?> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
// Assert
Awaitility.await()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(future::isDone);
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(future::isDone);
assertThat(outcome).isNull();
assertThreadNamePrefix(task);
}
@Test
void submitFailingListenableRunnable() {
void submitFailingListenableRunnable() throws Exception {
TestTask task = new TestTask(this.testName, 0);
ListenableFuture<?> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
Awaitility.await()
.dontCatchUncaughtExceptions()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
.dontCatchUncaughtExceptions()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
assertThat(outcome.getClass()).isSameAs(RuntimeException.class);
}
@@ -159,13 +159,14 @@ abstract class AbstractSchedulingTaskExecutorTests {
future1.get(1000, TimeUnit.MILLISECONDS);
}
catch (Exception ex) {
// ignore
/* ignore */
}
Awaitility.await()
.atMost(4, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.untilAsserted(() -> assertThatExceptionOfType(CancellationException.class)
.isThrownBy(() -> future2.get(1000, TimeUnit.MILLISECONDS)));
.atMost(4, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.untilAsserted(() ->
assertThatExceptionOfType(CancellationException.class).isThrownBy(() ->
future2.get(1000, TimeUnit.MILLISECONDS)));
}
@Test
@@ -177,11 +178,11 @@ abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
void submitFailingCallable() {
void submitFailingCallable() throws Exception {
TestCallable task = new TestCallable(this.testName, 0);
Future<String> future = executor.submit(task);
assertThatExceptionOfType(ExecutionException.class)
.isThrownBy(() -> future.get(1000, TimeUnit.MILLISECONDS));
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() ->
future.get(1000, TimeUnit.MILLISECONDS));
assertThat(future.isDone()).isTrue();
}
@@ -195,41 +196,42 @@ abstract class AbstractSchedulingTaskExecutorTests {
future1.get(1000, TimeUnit.MILLISECONDS);
}
catch (Exception ex) {
// ignore
/* ignore */
}
Awaitility.await()
.atMost(4, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.untilAsserted(() -> assertThatExceptionOfType(CancellationException.class)
.isThrownBy(() -> future2.get(1000, TimeUnit.MILLISECONDS)));
.atMost(4, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.untilAsserted(() ->
assertThatExceptionOfType(CancellationException.class).isThrownBy(() ->
future2.get(1000, TimeUnit.MILLISECONDS)));
}
@Test
void submitListenableCallable() {
void submitListenableCallable() throws Exception {
TestCallable task = new TestCallable(this.testName, 1);
// Act
ListenableFuture<String> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
// Assert
Awaitility.await()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
assertThat(outcome.toString().substring(0, this.threadNamePrefix.length())).isEqualTo(this.threadNamePrefix);
}
@Test
void submitFailingListenableCallable() {
void submitFailingListenableCallable() throws Exception {
TestCallable task = new TestCallable(this.testName, 0);
// Act
ListenableFuture<String> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
// Assert
Awaitility.await()
.dontCatchUncaughtExceptions()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
.dontCatchUncaughtExceptions()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
assertThat(outcome.getClass()).isSameAs(RuntimeException.class);
}
@@ -294,9 +296,8 @@ abstract class AbstractSchedulingTaskExecutorTests {
}
if (expectedRunCount >= 0) {
if (actualRunCount.incrementAndGet() > expectedRunCount) {
RuntimeException exception = new RuntimeException(String.format(
"%s failure for test '%s': expectedRunCount:<%d>, actualRunCount:<%d>",
getClass().getSimpleName(), this.testName, expectedRunCount, actualRunCount.get()));
RuntimeException exception = new RuntimeException(String.format("%s failure for test '%s': expectedRunCount:<%d>, actualRunCount:<%d>",
getClass().getSimpleName(), this.testName, expectedRunCount, actualRunCount.get()));
this.exception.set(exception);
throw exception;
}
@@ -328,9 +329,8 @@ abstract class AbstractSchedulingTaskExecutorTests {
}
if (expectedRunCount >= 0) {
if (actualRunCount.incrementAndGet() > expectedRunCount) {
throw new RuntimeException(String.format(
"%s failure for test '%s': expectedRunCount:<%d>, actualRunCount:<%d>",
getClass().getSimpleName(), this.testName, expectedRunCount, actualRunCount.get()));
throw new RuntimeException(String.format("%s failure for test '%s': expectedRunCount:<%d>, actualRunCount:<%d>",
getClass().getSimpleName(), this.testName, expectedRunCount, actualRunCount.get()));
}
}
return Thread.currentThread().getName();
@@ -89,24 +89,19 @@ class ConcurrentTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
private static class DecoratedRunnable implements Runnable {
@Override
public void run() {
}
}
private static class RunnableDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
return new DecoratedRunnable();
}
}
private static class DecoratedExecutor implements Executor {
@Override
public void execute(Runnable command) {
Assert.state(command instanceof DecoratedRunnable, "TaskDecorator not applied");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -41,14 +41,14 @@ import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
class ScheduledExecutorFactoryBeanTests {
@Test
void throwsExceptionIfPoolSizeIsLessThanZero() {
void throwsExceptionIfPoolSizeIsLessThanZero() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
assertThatIllegalArgumentException().isThrownBy(() -> factory.setPoolSize(-1));
}
@Test
@SuppressWarnings("serial")
void shutdownNowIsPropagatedToTheExecutorOnDestroy() {
void shutdownNowIsPropagatedToTheExecutorOnDestroy() throws Exception {
final ScheduledExecutorService executor = mock(ScheduledExecutorService.class);
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
@@ -66,7 +66,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@SuppressWarnings("serial")
void shutdownIsPropagatedToTheExecutorOnDestroy() {
void shutdownIsPropagatedToTheExecutorOnDestroy() throws Exception {
final ScheduledExecutorService executor = mock(ScheduledExecutorService.class);
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
@@ -85,7 +85,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(LONG_RUNNING)
void oneTimeExecutionIsSetUpAndFiresCorrectly() {
void oneTimeExecutionIsSetUpAndFiresCorrectly() throws Exception {
Runnable runnable = mock(Runnable.class);
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
@@ -99,7 +99,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(LONG_RUNNING)
void fixedRepeatedExecutionIsSetUpAndFiresCorrectly() {
void fixedRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception {
Runnable runnable = mock(Runnable.class);
ScheduledExecutorTask task = new ScheduledExecutorTask(runnable);
@@ -117,7 +117,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(LONG_RUNNING)
void fixedRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() {
void fixedRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception {
Runnable runnable = mock(Runnable.class);
willThrow(new IllegalStateException()).given(runnable).run();
@@ -137,7 +137,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(LONG_RUNNING)
void withInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectly() {
void withInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception {
Runnable runnable = mock(Runnable.class);
ScheduledExecutorTask task = new ScheduledExecutorTask(runnable);
@@ -157,7 +157,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(LONG_RUNNING)
void withInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() {
void withInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception {
Runnable runnable = mock(Runnable.class);
willThrow(new IllegalStateException()).given(runnable).run();
@@ -179,7 +179,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@SuppressWarnings("serial")
void settingThreadFactoryToNullForcesUseOfDefaultButIsOtherwiseCool() {
void settingThreadFactoryToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
@Override
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
@@ -195,7 +195,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@SuppressWarnings("serial")
void settingRejectedExecutionHandlerToNullForcesUseOfDefaultButIsOtherwiseCool() {
void settingRejectedExecutionHandlerToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
@Override
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
@@ -210,7 +210,7 @@ class ScheduledExecutorFactoryBeanTests {
}
@Test
void objectTypeReportsCorrectType() {
void objectTypeReportsCorrectType() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
assertThat(factory.getObjectType()).isEqualTo(ScheduledExecutorService.class);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -26,8 +26,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.InstanceOfAssertFactories.type;
/**
@@ -67,7 +67,8 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
assertThat(executor.getCorePoolSize()).isEqualTo(1);
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(1);
assertThatIllegalArgumentException().isThrownBy(() -> executor.setCorePoolSize(-1));
assertThatThrownBy(() -> executor.setCorePoolSize(-1))
.isInstanceOf(IllegalArgumentException.class);
assertThat(executor.getCorePoolSize()).isEqualTo(1);
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(1);
@@ -89,7 +90,8 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
assertThat(executor.getMaxPoolSize()).isEqualTo(1);
assertThat(executor.getThreadPoolExecutor().getMaximumPoolSize()).isEqualTo(1);
assertThatIllegalArgumentException().isThrownBy(() -> executor.setMaxPoolSize(0));
assertThatThrownBy(() -> executor.setMaxPoolSize(0))
.isInstanceOf(IllegalArgumentException.class);
assertThat(executor.getMaxPoolSize()).isEqualTo(1);
assertThat(executor.getThreadPoolExecutor().getMaximumPoolSize()).isEqualTo(1);
@@ -111,7 +113,8 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
assertThat(executor.getKeepAliveSeconds()).isEqualTo(60);
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(60);
assertThatIllegalArgumentException().isThrownBy(() -> executor.setKeepAliveSeconds(-10));
assertThatThrownBy(() -> executor.setKeepAliveSeconds(-10))
.isInstanceOf(IllegalArgumentException.class);
assertThat(executor.getKeepAliveSeconds()).isEqualTo(60);
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(60);
@@ -121,8 +124,8 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
void queueCapacityDefault() {
assertThat(executor.getQueueCapacity()).isEqualTo(Integer.MAX_VALUE);
assertThat(executor.getThreadPoolExecutor().getQueue())
.asInstanceOf(type(LinkedBlockingQueue.class))
.extracting(BlockingQueue::remainingCapacity).isEqualTo(Integer.MAX_VALUE);
.asInstanceOf(type(LinkedBlockingQueue.class))
.extracting(BlockingQueue::remainingCapacity).isEqualTo(Integer.MAX_VALUE);
}
@Test
@@ -132,8 +135,8 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
assertThat(executor.getQueueCapacity()).isZero();
assertThat(executor.getThreadPoolExecutor().getQueue())
.asInstanceOf(type(SynchronousQueue.class))
.extracting(BlockingQueue::remainingCapacity).isEqualTo(0);
.asInstanceOf(type(SynchronousQueue.class))
.extracting(BlockingQueue::remainingCapacity).isEqualTo(0);
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -95,11 +95,11 @@ class DataBinderTests {
binder.bind(pvs);
binder.close();
assertThat(rod.getName()).as("changed name correctly").isEqualTo("Rod");
assertThat(rod.getAge()).as("changed age correctly").isEqualTo(32);
assertThat(rod.getName().equals("Rod")).as("changed name correctly").isTrue();
assertThat(rod.getAge() == 32).as("changed age correctly").isTrue();
Map<?, ?> map = binder.getBindingResult().getModel();
assertThat(map).as("There is one element in map").hasSize(2);
assertThat(map.size() == 2).as("There is one element in map").isTrue();
TestBean tb = (TestBean) map.get("person");
assertThat(tb.equals(rod)).as("Same object").isTrue();
@@ -157,9 +157,8 @@ class DataBinderTests {
pvs.add("name", "Rod");
pvs.add("age", 32);
pvs.add("nonExisting", "someValue");
assertThatExceptionOfType(NotWritablePropertyException.class)
.isThrownBy(() -> binder.bind(pvs));
assertThatExceptionOfType(NotWritablePropertyException.class).isThrownBy(() ->
binder.bind(pvs));
}
@Test
@@ -169,9 +168,8 @@ class DataBinderTests {
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("name", "Rod");
pvs.add("spouse.age", 32);
assertThatExceptionOfType(NullValueInNestedPathException.class)
.isThrownBy(() -> binder.bind(pvs));
assertThatExceptionOfType(NullValueInNestedPathException.class).isThrownBy(() ->
binder.bind(pvs));
}
@Test
@@ -199,56 +197,57 @@ class DataBinderTests {
pvs.add("age", "32x");
pvs.add("touchy", "m.y");
binder.bind(pvs);
assertThatExceptionOfType(BindException.class).isThrownBy(
binder::close)
.satisfies(ex -> {
assertThat(rod.getName()).isEqualTo("Rod");
Map<?, ?> map = binder.getBindingResult().getModel();
TestBean tb = (TestBean) map.get("person");
assertThat(tb).isSameAs(rod);
assertThatExceptionOfType(BindException.class).isThrownBy(binder::close).satisfies(ex -> {
assertThat(rod.getName()).isEqualTo("Rod");
Map<?, ?> map = binder.getBindingResult().getModel();
TestBean tb = (TestBean) map.get("person");
assertThat(tb).isSameAs(rod);
BindingResult br = (BindingResult) map.get(BindingResult.MODEL_KEY_PREFIX + "person");
assertThat(BindingResultUtils.getBindingResult(map, "person")).isEqualTo(br);
assertThat(BindingResultUtils.getRequiredBindingResult(map, "person")).isEqualTo(br);
BindingResult br = (BindingResult) map.get(BindingResult.MODEL_KEY_PREFIX + "person");
assertThat(BindingResultUtils.getBindingResult(map, "person")).isEqualTo(br);
assertThat(BindingResultUtils.getRequiredBindingResult(map, "person")).isEqualTo(br);
assertThat(BindingResultUtils.getBindingResult(map, "someOtherName")).isNull();
assertThatIllegalStateException().isThrownBy(() ->
BindingResultUtils.getRequiredBindingResult(map, "someOtherName"));
assertThat(BindingResultUtils.getBindingResult(map, "someOtherName")).isNull();
assertThatIllegalStateException().isThrownBy(() ->
BindingResultUtils.getRequiredBindingResult(map, "someOtherName"));
assertThat(binder.getBindingResult()).as("Added itself to map").isSameAs(br);
assertThat(br.hasErrors()).isTrue();
assertThat(br.getErrorCount()).isEqualTo(2);
assertThat(binder.getBindingResult()).as("Added itself to map").isSameAs(br);
assertThat(br.hasErrors()).isTrue();
assertThat(br.getErrorCount()).isEqualTo(2);
assertThat(br.hasFieldErrors("age")).isTrue();
assertThat(br.getFieldErrorCount("age")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("age")).isEqualTo("32x");
FieldError ageError = binder.getBindingResult().getFieldError("age");
assertThat(ageError).isNotNull();
assertThat(ageError.getCode()).isEqualTo("typeMismatch");
assertThat(ageError.getRejectedValue()).isEqualTo("32x");
assertThat(ageError.contains(TypeMismatchException.class)).isTrue();
assertThat(ageError.contains(NumberFormatException.class)).isTrue();
assertThat(ageError.unwrap(NumberFormatException.class).getMessage()).contains("32x");
assertThat(tb.getAge()).isEqualTo(0);
assertThat(br.hasFieldErrors("age")).isTrue();
assertThat(br.getFieldErrorCount("age")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("age")).isEqualTo("32x");
FieldError ageError = binder.getBindingResult().getFieldError("age");
assertThat(ageError).isNotNull();
assertThat(ageError.getCode()).isEqualTo("typeMismatch");
assertThat(ageError.getRejectedValue()).isEqualTo("32x");
assertThat(ageError.contains(TypeMismatchException.class)).isTrue();
assertThat(ageError.contains(NumberFormatException.class)).isTrue();
assertThat(ageError.unwrap(NumberFormatException.class).getMessage()).contains("32x");
assertThat(tb.getAge()).isEqualTo(0);
assertThat(br.hasFieldErrors("touchy")).isTrue();
assertThat(br.getFieldErrorCount("touchy")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("touchy")).isEqualTo("m.y");
FieldError touchyError = binder.getBindingResult().getFieldError("touchy");
assertThat(touchyError).isNotNull();
assertThat(touchyError.getCode()).isEqualTo("methodInvocation");
assertThat(touchyError.getRejectedValue()).isEqualTo("m.y");
assertThat(touchyError.contains(MethodInvocationException.class)).isTrue();
assertThat(touchyError.unwrap(MethodInvocationException.class).getCause().getMessage()).contains("a .");
assertThat(tb.getTouchy()).isNull();
assertThat(br.hasFieldErrors("touchy")).isTrue();
assertThat(br.getFieldErrorCount("touchy")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("touchy")).isEqualTo("m.y");
FieldError touchyError = binder.getBindingResult().getFieldError("touchy");
assertThat(touchyError).isNotNull();
assertThat(touchyError.getCode()).isEqualTo("methodInvocation");
assertThat(touchyError.getRejectedValue()).isEqualTo("m.y");
assertThat(touchyError.contains(MethodInvocationException.class)).isTrue();
assertThat(touchyError.unwrap(MethodInvocationException.class).getCause().getMessage()).contains("a .");
assertThat(tb.getTouchy()).isNull();
DataBinder binder2 = new DataBinder(new TestBean(), "person");
MutablePropertyValues pvs2 = new MutablePropertyValues();
pvs2.add("name", "Rod");
pvs2.add("age", "32x");
pvs2.add("touchy", "m.y");
binder2.bind(pvs2);
assertThat(ex.getBindingResult()).isEqualTo(binder2.getBindingResult());
});
DataBinder binder2 = new DataBinder(new TestBean(), "person");
MutablePropertyValues pvs2 = new MutablePropertyValues();
pvs2.add("name", "Rod");
pvs2.add("age", "32x");
pvs2.add("touchy", "m.y");
binder2.bind(pvs2);
assertThat(ex.getBindingResult()).isEqualTo(binder2.getBindingResult());
});
}
@Test
@@ -258,17 +257,15 @@ class DataBinderTests {
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("class.classLoader.URLs[0]", "https://myserver");
binder.setIgnoreUnknownFields(false);
assertThatExceptionOfType(NotWritablePropertyException.class)
.isThrownBy(() -> binder.bind(pvs))
.withMessageContaining("classLoader");
assertThatExceptionOfType(NotWritablePropertyException.class).isThrownBy(() ->
binder.bind(pvs))
.withMessageContaining("classLoader");
}
@Test
void bindingWithErrorsAndCustomEditors() {
TestBean rod = new TestBean();
DataBinder binder = new DataBinder(rod, "person");
binder.registerCustomEditor(String.class, "touchy", new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
@@ -289,7 +286,6 @@ class DataBinderTests {
return ((TestBean) getValue()).getName();
}
});
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("name", "Rod");
pvs.add("age", "32x");
@@ -297,39 +293,41 @@ class DataBinderTests {
pvs.add("spouse", "Kerry");
binder.bind(pvs);
assertThatExceptionOfType(BindException.class).isThrownBy(binder::close).satisfies(ex -> {
assertThat(rod.getName()).isEqualTo("Rod");
Map<?, ?> model = binder.getBindingResult().getModel();
TestBean tb = (TestBean) model.get("person");
assertThat(tb).isEqualTo(rod);
assertThatExceptionOfType(BindException.class).isThrownBy(
binder::close)
.satisfies(ex -> {
assertThat(rod.getName()).isEqualTo("Rod");
Map<?, ?> model = binder.getBindingResult().getModel();
TestBean tb = (TestBean) model.get("person");
assertThat(tb).isEqualTo(rod);
BindingResult br = (BindingResult) model.get(BindingResult.MODEL_KEY_PREFIX + "person");
assertThat(binder.getBindingResult()).isSameAs(br);
assertThat(br.hasErrors()).isTrue();
assertThat(br.getErrorCount()).isEqualTo(2);
BindingResult br = (BindingResult) model.get(BindingResult.MODEL_KEY_PREFIX + "person");
assertThat(binder.getBindingResult()).isSameAs(br);
assertThat(br.hasErrors()).isTrue();
assertThat(br.getErrorCount()).isEqualTo(2);
assertThat(br.hasFieldErrors("age")).isTrue();
assertThat(br.getFieldErrorCount("age")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("age")).isEqualTo("32x");
FieldError ageError = binder.getBindingResult().getFieldError("age");
assertThat(ageError).isNotNull();
assertThat(ageError.getCode()).isEqualTo("typeMismatch");
assertThat(ageError.getRejectedValue()).isEqualTo("32x");
assertThat(tb.getAge()).isEqualTo(0);
assertThat(br.hasFieldErrors("age")).isTrue();
assertThat(br.getFieldErrorCount("age")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("age")).isEqualTo("32x");
FieldError ageError = binder.getBindingResult().getFieldError("age");
assertThat(ageError).isNotNull();
assertThat(ageError.getCode()).isEqualTo("typeMismatch");
assertThat(ageError.getRejectedValue()).isEqualTo("32x");
assertThat(tb.getAge()).isEqualTo(0);
assertThat(br.hasFieldErrors("touchy")).isTrue();
assertThat(br.getFieldErrorCount("touchy")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("touchy")).isEqualTo("m.y");
FieldError touchyError = binder.getBindingResult().getFieldError("touchy");
assertThat(touchyError).isNotNull();
assertThat(touchyError.getCode()).isEqualTo("methodInvocation");
assertThat(touchyError.getRejectedValue()).isEqualTo("m.y");
assertThat(tb.getTouchy()).isNull();
assertThat(br.hasFieldErrors("touchy")).isTrue();
assertThat(br.getFieldErrorCount("touchy")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("touchy")).isEqualTo("m.y");
FieldError touchyError = binder.getBindingResult().getFieldError("touchy");
assertThat(touchyError).isNotNull();
assertThat(touchyError.getCode()).isEqualTo("methodInvocation");
assertThat(touchyError.getRejectedValue()).isEqualTo("m.y");
assertThat(tb.getTouchy()).isNull();
assertThat(br.hasFieldErrors("spouse")).isFalse();
assertThat(binder.getBindingResult().getFieldValue("spouse")).isEqualTo("Kerry");
assertThat(tb.getSpouse()).isNotNull();
});
assertThat(br.hasFieldErrors("spouse")).isFalse();
assertThat(binder.getBindingResult().getFieldValue("spouse")).isEqualTo("Kerry");
assertThat(tb.getSpouse()).isNotNull();
});
}
@Test
@@ -578,7 +576,7 @@ class DataBinderTests {
editor = binder.getBindingResult().findEditor("myFloat", null);
assertThat(editor).isNotNull();
editor.setAsText("1,6");
assertThat(((Number) editor.getValue()).floatValue()).isEqualTo(1.6f);
assertThat(((Number) editor.getValue()).floatValue() == 1.6f).isTrue();
}
finally {
LocaleContextHolder.resetLocaleContext();
@@ -754,15 +752,15 @@ class DataBinderTests {
binder.bind(pvs);
binder.close();
assertThat(rod.getName()).as("changed name correctly").isEqualTo("Rod");
assertThat(rod.getTouchy()).as("changed touchy correctly").isEqualTo("Rod");
assertThat(rod.getAge()).as("did not change age").isEqualTo(0);
assertThat("Rod".equals(rod.getName())).as("changed name correctly").isTrue();
assertThat("Rod".equals(rod.getTouchy())).as("changed touchy correctly").isTrue();
assertThat(rod.getAge() == 0).as("did not change age").isTrue();
String[] disallowedFields = binder.getBindingResult().getSuppressedFields();
assertThat(disallowedFields).hasSize(1);
assertThat(disallowedFields[0]).isEqualTo("age");
Map<?,?> m = binder.getBindingResult().getModel();
assertThat(m).as("There is one element in map").hasSize(2);
assertThat(m.size() == 2).as("There is one element in map").isTrue();
TestBean tb = (TestBean) m.get("person");
assertThat(tb.equals(rod)).as("Same object").isTrue();
}
@@ -916,7 +914,7 @@ class DataBinderTests {
binder.getBindingResult().rejectValue("touchy", "someCode", "someMessage");
binder.getBindingResult().rejectValue("spouse.name", "someCode", "someMessage");
assertThat(binder.getBindingResult().getNestedPath()).isEmpty();
assertThat(binder.getBindingResult().getNestedPath()).isEqualTo("");
assertThat(binder.getBindingResult().getFieldValue("name")).isEqualTo("value");
assertThat(binder.getBindingResult().getFieldError("name").getRejectedValue()).isEqualTo("prefixvalue");
assertThat(tb.getName()).isEqualTo("prefixvalue");
@@ -1012,7 +1010,7 @@ class DataBinderTests {
binder.getBindingResult().rejectValue("touchy", "someCode", "someMessage");
binder.getBindingResult().rejectValue("spouse.name", "someCode", "someMessage");
assertThat(binder.getBindingResult().getNestedPath()).isEmpty();
assertThat(binder.getBindingResult().getNestedPath()).isEqualTo("");
assertThat(binder.getBindingResult().getFieldValue("name")).isEqualTo("value");
assertThat(binder.getBindingResult().getFieldError("name").getRejectedValue()).isEqualTo("prefixvalue");
assertThat(tb.getName()).isEqualTo("prefixvalue");
@@ -1136,11 +1134,12 @@ class DataBinderTests {
tb2.setAge(34);
tb.setSpouse(tb2);
DataBinder db = new DataBinder(tb, "tb");
db.setValidator(new TestBeanValidator());
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("spouse.age", "argh");
db.bind(pvs);
Errors errors = db.getBindingResult();
Validator testValidator = new TestBeanValidator();
testValidator.validate(tb, errors);
errors.setNestedPath("spouse");
assertThat(errors.getNestedPath()).isEqualTo("spouse.");
@@ -1149,7 +1148,7 @@ class DataBinderTests {
spouseValidator.validate(tb.getSpouse(), errors);
errors.setNestedPath("");
assertThat(errors.getNestedPath()).isEmpty();
assertThat(errors.getNestedPath()).isEqualTo("");
errors.pushNestedPath("spouse");
assertThat(errors.getNestedPath()).isEqualTo("spouse.");
errors.pushNestedPath("spouse");
@@ -1157,7 +1156,7 @@ class DataBinderTests {
errors.popNestedPath();
assertThat(errors.getNestedPath()).isEqualTo("spouse.");
errors.popNestedPath();
assertThat(errors.getNestedPath()).isEmpty();
assertThat(errors.getNestedPath()).isEqualTo("");
try {
errors.popNestedPath();
}
@@ -1167,7 +1166,7 @@ class DataBinderTests {
errors.pushNestedPath("spouse");
assertThat(errors.getNestedPath()).isEqualTo("spouse.");
errors.setNestedPath("");
assertThat(errors.getNestedPath()).isEmpty();
assertThat(errors.getNestedPath()).isEqualTo("");
try {
errors.popNestedPath();
}
@@ -1188,7 +1187,8 @@ class DataBinderTests {
void validatorWithErrors() {
TestBean tb = new TestBean();
tb.setSpouse(new TestBean());
Errors errors = new DataBinder(tb, "tb").getBindingResult();
Errors errors = new BeanPropertyBindingResult(tb, "tb");
Validator testValidator = new TestBeanValidator();
testValidator.validate(tb, errors);
@@ -1201,11 +1201,7 @@ class DataBinderTests {
errors.setNestedPath("");
assertThat(errors.hasErrors()).isTrue();
assertThat(errors.getErrorCount()).isEqualTo(6);
assertThat(errors.getAllErrors())
.containsAll(errors.getGlobalErrors())
.containsAll(errors.getFieldErrors());
assertThat(errors.hasGlobalErrors()).isTrue();
assertThat(errors.getGlobalErrorCount()).isEqualTo(2);
assertThat(errors.getGlobalError().getCode()).isEqualTo("NAME_TOUCHY_MISMATCH");
assertThat((errors.getGlobalErrors().get(0)).getCode()).isEqualTo("NAME_TOUCHY_MISMATCH");
@@ -1261,11 +1257,10 @@ class DataBinderTests {
TestBean tb = new TestBean();
tb.setSpouse(new TestBean());
DataBinder dataBinder = new DataBinder(tb, "tb");
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(tb, "tb");
DefaultMessageCodesResolver codesResolver = new DefaultMessageCodesResolver();
codesResolver.setPrefix("validation.");
dataBinder.setMessageCodesResolver(codesResolver);
Errors errors = dataBinder.getBindingResult();
errors.setMessageCodesResolver(codesResolver);
Validator testValidator = new TestBeanValidator();
testValidator.validate(tb, errors);
@@ -1278,11 +1273,7 @@ class DataBinderTests {
errors.setNestedPath("");
assertThat(errors.hasErrors()).isTrue();
assertThat(errors.getErrorCount()).isEqualTo(6);
assertThat(errors.getAllErrors())
.containsAll(errors.getGlobalErrors())
.containsAll(errors.getFieldErrors());
assertThat(errors.hasGlobalErrors()).isTrue();
assertThat(errors.getGlobalErrorCount()).isEqualTo(2);
assertThat(errors.getGlobalError().getCode()).isEqualTo("validation.NAME_TOUCHY_MISMATCH");
assertThat((errors.getGlobalErrors().get(0)).getCode()).isEqualTo("validation.NAME_TOUCHY_MISMATCH");
@@ -1336,11 +1327,9 @@ class DataBinderTests {
@Test
void validatorWithNestedObjectNull() {
TestBean tb = new TestBean();
Errors errors = new DataBinder(tb, "tb").getBindingResult();
Errors errors = new BeanPropertyBindingResult(tb, "tb");
Validator testValidator = new TestBeanValidator();
testValidator.validate(tb, errors);
errors.setNestedPath("spouse.");
assertThat(errors.getNestedPath()).isEqualTo("spouse.");
Validator spouseValidator = new SpouseValidator();
@@ -1735,7 +1724,7 @@ class DataBinderTests {
pvs.add("stringArray", new String[] {"a1", "b2"});
binder.bind(pvs);
assertThat(binder.getBindingResult().hasErrors()).isFalse();
assertThat(tb.getStringArray()).hasSize(2);
assertThat(tb.getStringArray().length).isEqualTo(2);
assertThat(tb.getStringArray()[0]).isEqualTo("Xa1");
assertThat(tb.getStringArray()[1]).isEqualTo("Xb2");
}
@@ -1811,16 +1800,16 @@ class DataBinderTests {
tb.setName("myName");
tb.setAge(99);
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(tb, "tb");
errors.reject("invalid");
errors.rejectValue("age", "invalidField");
BeanPropertyBindingResult ex = new BeanPropertyBindingResult(tb, "tb");
ex.reject("invalid");
ex.rejectValue("age", "invalidField");
StaticMessageSource ms = new StaticMessageSource();
ms.addMessage("invalid", Locale.US, "general error");
ms.addMessage("invalidField", Locale.US, "invalid field");
assertThat(ms.getMessage(errors.getGlobalError(), Locale.US)).isEqualTo("general error");
assertThat(ms.getMessage(errors.getFieldError("age"), Locale.US)).isEqualTo("invalid field");
assertThat(ms.getMessage(ex.getGlobalError(), Locale.US)).isEqualTo("general error");
assertThat(ms.getMessage(ex.getFieldError("age"), Locale.US)).isEqualTo("invalid field");
}
@Test
@@ -1888,13 +1877,13 @@ class DataBinderTests {
void autoGrowBeyondDefaultLimit() {
TestBean testBean = new TestBean();
DataBinder binder = new DataBinder(testBean, "testBean");
MutablePropertyValues mpvs = new MutablePropertyValues();
mpvs.add("friends[256]", "");
assertThatExceptionOfType(InvalidPropertyException.class)
.isThrownBy(() -> binder.bind(mpvs))
.havingRootCause()
.isInstanceOf(IndexOutOfBoundsException.class);
.isThrownBy(() -> binder.bind(mpvs))
.havingRootCause()
.isInstanceOf(IndexOutOfBoundsException.class);
}
@Test
@@ -1915,13 +1904,13 @@ class DataBinderTests {
TestBean testBean = new TestBean();
DataBinder binder = new DataBinder(testBean, "testBean");
binder.setAutoGrowCollectionLimit(10);
MutablePropertyValues mpvs = new MutablePropertyValues();
mpvs.add("friends[16]", "");
assertThatExceptionOfType(InvalidPropertyException.class)
.isThrownBy(() -> binder.bind(mpvs))
.havingRootCause()
.isInstanceOf(IndexOutOfBoundsException.class);
.isThrownBy(() -> binder.bind(mpvs))
.havingRootCause()
.isInstanceOf(IndexOutOfBoundsException.class);
}
@Test
@@ -1937,7 +1926,7 @@ class DataBinderTests {
List<Object> list = (List<Object>) form.getF().get("list");
assertThat(list.get(0)).isEqualTo("firstValue");
assertThat(list.get(1)).isEqualTo("secondValue");
assertThat(list).hasSize(2);
assertThat(list.size()).isEqualTo(2);
}
@Test
@@ -1970,7 +1959,7 @@ class DataBinderTests {
pvs.add("integerList[256]", "1");
binder.bind(pvs);
assertThat(tb.getIntegerList()).hasSize(257);
assertThat(tb.getIntegerList().size()).isEqualTo(257);
assertThat(tb.getIntegerList().get(256)).isEqualTo(Integer.valueOf(1));
assertThat(binder.getBindingResult().getFieldValue("integerList[256]")).isEqualTo(1);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
public class ValidationUtilsTests {
@Test
public void testInvokeValidatorWithNullValidator() {
public void testInvokeValidatorWithNullValidator() throws Exception {
TestBean tb = new TestBean();
Errors errors = new BeanPropertyBindingResult(tb, "tb");
assertThatIllegalArgumentException().isThrownBy(() ->
@@ -43,14 +43,14 @@ public class ValidationUtilsTests {
}
@Test
public void testInvokeValidatorWithNullErrors() {
public void testInvokeValidatorWithNullErrors() throws Exception {
TestBean tb = new TestBean();
assertThatIllegalArgumentException().isThrownBy(() ->
ValidationUtils.invokeValidator(new EmptyValidator(), tb, null));
}
@Test
public void testInvokeValidatorSunnyDay() {
public void testInvokeValidatorSunnyDay() throws Exception {
TestBean tb = new TestBean();
Errors errors = new BeanPropertyBindingResult(tb, "tb");
ValidationUtils.invokeValidator(new EmptyValidator(), tb, errors);
@@ -59,7 +59,7 @@ public class ValidationUtilsTests {
}
@Test
public void testValidationUtilsSunnyDay() {
public void testValidationUtilsSunnyDay() throws Exception {
TestBean tb = new TestBean("");
Validator testValidator = new EmptyValidator();
@@ -75,7 +75,7 @@ public class ValidationUtilsTests {
}
@Test
public void testValidationUtilsNull() {
public void testValidationUtilsNull() throws Exception {
TestBean tb = new TestBean();
Errors errors = new BeanPropertyBindingResult(tb, "tb");
Validator testValidator = new EmptyValidator();
@@ -85,7 +85,7 @@ public class ValidationUtilsTests {
}
@Test
public void testValidationUtilsEmpty() {
public void testValidationUtilsEmpty() throws Exception {
TestBean tb = new TestBean("");
Errors errors = new BeanPropertyBindingResult(tb, "tb");
Validator testValidator = new EmptyValidator();
@@ -113,7 +113,7 @@ public class ValidationUtilsTests {
}
@Test
public void testValidationUtilsEmptyOrWhitespace() {
public void testValidationUtilsEmptyOrWhitespace() throws Exception {
TestBean tb = new TestBean();
Validator testValidator = new EmptyOrWhitespaceValidator();
@@ -576,17 +576,15 @@ public class ReflectUtils {
c = (Class) lookupDefineClassMethod.invoke(lookup, b);
}
catch (InvocationTargetException ex) {
Throwable target = ex.getTargetException();
if (target.getClass() != LinkageError.class && target.getClass() != IllegalAccessException.class) {
throw new CodeGenerationException(target);
}
throw new CodeGenerationException(target) {
throw new CodeGenerationException(ex.getTargetException());
}
catch (IllegalAccessException ex) {
throw new CodeGenerationException(ex) {
@Override
public String getMessage() {
return "ClassLoader mismatch for [" + contextClass.getName() +
"]: JVM should be started with --add-opens=java.base/java.lang=ALL-UNNAMED " +
"for ClassLoader.defineClass to be accessible on " + loader.getClass().getName() +
"; consider co-locating the affected class in that target ClassLoader instead.";
"for ClassLoader.defineClass to be accessible on " + loader.getClass().getName();
}
};
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -74,8 +74,7 @@ public final class MethodIntrospector {
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || bridgedMethod == method ||
metadataLookup.inspect(bridgedMethod) == null) {
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
methodMap.put(specificMethod, result);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -14,6 +14,7 @@
* limitations under the License.
*/
package org.springframework.core;
import java.lang.reflect.ParameterizedType;
@@ -91,7 +92,8 @@ public abstract class ParameterizedTypeReference<T> {
* @since 4.3.12
*/
public static <T> ParameterizedTypeReference<T> forType(Type type) {
return new ParameterizedTypeReference<T>(type) {};
return new ParameterizedTypeReference<T>(type) {
};
}
private static Class<?> findParameterizedTypeReferenceSubclass(Class<?> child) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -24,6 +24,8 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.function.Function;
import kotlinx.coroutines.CompletableDeferredKt;
import kotlinx.coroutines.Deferred;
import org.reactivestreams.Publisher;
import reactor.blockhound.BlockHound;
import reactor.blockhound.integration.BlockHoundIntegration;
@@ -37,14 +39,13 @@ import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ReflectionUtils;
/**
* A registry of adapters to adapt Reactive Streams {@link Publisher} to/from various
* async/reactive types such as {@code CompletableFuture}, RxJava {@code Flowable}, etc.
* This is designed to complement Spring's Reactor {@code Mono}/{@code Flux} support while
* also being usable without Reactor, e.g. just for {@code org.reactivestreams} bridging.
* A registry of adapters to adapt Reactive Streams {@link Publisher} to/from
* various async/reactive types such as {@code CompletableFuture}, RxJava
* {@code Flowable}, and others.
*
* <p>By default, depending on classpath availability, adapters are registered for Reactor
* (including {@code CompletableFuture} and {@code Flow.Publisher} adapters), RxJava 3,
* Kotlin Coroutines' {@code Deferred} (bridged via Reactor) and SmallRye Mutiny 1.x.
* <p>By default, depending on classpath availability, adapters are registered
* for Reactor, RxJava 3, {@link CompletableFuture}, {@code Flow.Publisher},
* and Kotlin Coroutines' {@code Deferred} and {@code Flow}.
*
* <p><strong>Note:</strong> As of Spring Framework 5.3.11, support for
* RxJava 1.x and 2.x is deprecated in favor of RxJava 3.
@@ -135,45 +136,16 @@ public class ReactiveAdapterRegistry {
* Register a reactive type along with functions to adapt to and from a
* Reactive Streams {@link Publisher}. The function arguments assume that
* their input is neither {@code null} nor {@link Optional}.
* <p>This variant registers the new adapter after existing adapters.
* It will be matched for the exact reactive type if no earlier adapter was
* registered for the specific type, and it will be matched for assignability
* in a second pass if no earlier adapter had an assignable type before.
* @see #registerReactiveTypeOverride
* @see #getAdapter
*/
public void registerReactiveType(ReactiveTypeDescriptor descriptor,
Function<Object, Publisher<?>> toAdapter, Function<Publisher<?>, Object> fromAdapter) {
this.adapters.add(buildAdapter(descriptor, toAdapter, fromAdapter));
}
/**
* Register a reactive type along with functions to adapt to and from a
* Reactive Streams {@link Publisher}. The function arguments assume that
* their input is neither {@code null} nor {@link Optional}.
* <p>This variant registers the new adapter first, effectively overriding
* any previously registered adapters for the same reactive type. This allows
* for overriding existing adapters, in particular default adapters.
* <p>Note that existing adapters for specific types will still match before
* an assignability match with the new adapter. In order to override all
* existing matches, a new reactive type adapter needs to be registered
* for every specific type, not relying on subtype assignability matches.
* @since 5.3.30
* @see #registerReactiveType
* @see #getAdapter
*/
public void registerReactiveTypeOverride(ReactiveTypeDescriptor descriptor,
Function<Object, Publisher<?>> toAdapter, Function<Publisher<?>, Object> fromAdapter) {
this.adapters.add(0, buildAdapter(descriptor, toAdapter, fromAdapter));
}
private ReactiveAdapter buildAdapter(ReactiveTypeDescriptor descriptor,
Function<Object, Publisher<?>> toAdapter, Function<Publisher<?>, Object> fromAdapter) {
return (reactorPresent ? new ReactorAdapter(descriptor, toAdapter, fromAdapter) :
new ReactiveAdapter(descriptor, toAdapter, fromAdapter));
if (reactorPresent) {
this.adapters.add(new ReactorAdapter(descriptor, toAdapter, fromAdapter));
}
else {
this.adapters.add(new ReactiveAdapter(descriptor, toAdapter, fromAdapter));
}
}
/**
@@ -429,9 +401,9 @@ public class ReactiveAdapterRegistry {
@SuppressWarnings("KotlinInternalInJava")
void registerAdapters(ReactiveAdapterRegistry registry) {
registry.registerReactiveType(
ReactiveTypeDescriptor.singleOptionalValue(kotlinx.coroutines.Deferred.class,
() -> kotlinx.coroutines.CompletableDeferredKt.CompletableDeferred(null)),
source -> CoroutinesUtils.deferredToMono((kotlinx.coroutines.Deferred<?>) source),
ReactiveTypeDescriptor.singleOptionalValue(Deferred.class,
() -> CompletableDeferredKt.CompletableDeferred(null)),
source -> CoroutinesUtils.deferredToMono((Deferred<?>) source),
source -> CoroutinesUtils.monoToDeferred(Mono.from(source)));
registry.registerReactiveType(
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -37,7 +37,7 @@ public final class ReactiveTypeDescriptor {
private final boolean noValue;
@Nullable
private final Supplier<?> emptySupplier;
private final Supplier<?> emptyValueSupplier;
private final boolean deferred;
@@ -55,7 +55,7 @@ public final class ReactiveTypeDescriptor {
this.reactiveType = reactiveType;
this.multiValue = multiValue;
this.noValue = noValue;
this.emptySupplier = emptySupplier;
this.emptyValueSupplier = emptySupplier;
this.deferred = deferred;
}
@@ -89,16 +89,16 @@ public final class ReactiveTypeDescriptor {
* Return {@code true} if the reactive type can complete with no values.
*/
public boolean supportsEmpty() {
return (this.emptySupplier != null);
return (this.emptyValueSupplier != null);
}
/**
* Return an empty-value instance for the underlying reactive or async type.
* <p>Use of this type implies {@link #supportsEmpty()} is {@code true}.
* Use of this type implies {@link #supportsEmpty()} is {@code true}.
*/
public Object getEmptyValue() {
Assert.state(this.emptySupplier != null, "Empty values not supported");
return this.emptySupplier.get();
Assert.state(this.emptyValueSupplier != null, "Empty values not supported");
return this.emptyValueSupplier.get();
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -133,9 +133,6 @@ public class ResolvableType implements Serializable {
@Nullable
private volatile ResolvableType[] generics;
@Nullable
private volatile Boolean unresolvableGenerics;
/**
* Private constructor used to create a new {@link ResolvableType} for cache key purposes,
@@ -548,15 +545,6 @@ public class ResolvableType implements Serializable {
if (this == NONE) {
return false;
}
Boolean unresolvableGenerics = this.unresolvableGenerics;
if (unresolvableGenerics == null) {
unresolvableGenerics = determineUnresolvableGenerics();
this.unresolvableGenerics = unresolvableGenerics;
}
return unresolvableGenerics;
}
private boolean determineUnresolvableGenerics() {
ResolvableType[] generics = getGenerics();
for (ResolvableType generic : generics) {
if (generic.isUnresolvableTypeVariable() || generic.isWildcardWithoutBounds()) {
@@ -568,7 +556,7 @@ public class ResolvableType implements Serializable {
try {
for (Type genericInterface : resolved.getGenericInterfaces()) {
if (genericInterface instanceof Class) {
if (((Class<?>) genericInterface).getTypeParameters().length > 0) {
if (forClass((Class<?>) genericInterface).hasGenerics()) {
return true;
}
}
@@ -577,10 +565,7 @@ public class ResolvableType implements Serializable {
catch (TypeNotPresentException ex) {
// Ignore non-present types in generic signature
}
Class<?> superclass = resolved.getSuperclass();
if (superclass != null && superclass != Object.class) {
return getSuperType().hasUnresolvableGenerics();
}
return getSuperType().hasUnresolvableGenerics();
}
return false;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -22,6 +22,7 @@ import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
@@ -203,18 +204,19 @@ final class SerializableTypeWrapper {
return forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, -1));
}
else if (Type[].class == method.getReturnType() && ObjectUtils.isEmpty(args)) {
Object returnValue = ReflectionUtils.invokeMethod(method, this.provider.getType());
if (returnValue == null) {
return null;
}
Type[] result = new Type[((Type[]) returnValue).length];
Type[] result = new Type[((Type[]) method.invoke(this.provider.getType())).length];
for (int i = 0; i < result.length; i++) {
result[i] = forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, i));
}
return result;
}
return ReflectionUtils.invokeMethod(method, this.provider.getType(), args);
try {
return method.invoke(this.provider.getType(), args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -149,8 +149,8 @@ public abstract class AnnotationUtils {
* @since 5.2
* @see #isCandidateClass(Class, String)
*/
public static boolean isCandidateClass(Class<?> clazz, @Nullable Class<? extends Annotation> annotationType) {
return (annotationType != null && isCandidateClass(clazz, annotationType.getName()));
public static boolean isCandidateClass(Class<?> clazz, Class<? extends Annotation> annotationType) {
return isCandidateClass(clazz, annotationType.getName());
}
/**
@@ -1321,9 +1321,6 @@ public abstract class AnnotationUtils {
public static void clearCache() {
AnnotationTypeMappings.clearCache();
AnnotationsScanner.clearCache();
AttributeMethods.cache.clear();
RepeatableContainers.cache.clear();
OrderUtils.orderCache.clear();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -39,7 +39,9 @@ final class AttributeMethods {
static final AttributeMethods NONE = new AttributeMethods(null, new Method[0]);
static final Map<Class<? extends Annotation>, AttributeMethods> cache = new ConcurrentReferenceHashMap<>();
private static final Map<Class<? extends Annotation>, AttributeMethods> cache =
new ConcurrentReferenceHashMap<>();
private static final Comparator<Method> methodComparator = (m1, m2) -> {
if (m1 != null && m2 != null) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -41,7 +41,7 @@ public abstract class OrderUtils {
private static final String JAVAX_PRIORITY_ANNOTATION = "javax.annotation.Priority";
/** Cache for @Order value (or NOT_ANNOTATED marker) per Class. */
static final Map<AnnotatedElement, Object> orderCache = new ConcurrentReferenceHashMap<>(64);
private static final Map<AnnotatedElement, Object> orderCache = new ConcurrentReferenceHashMap<>(64);
/**
@@ -43,8 +43,6 @@ import org.springframework.util.ObjectUtils;
*/
public abstract class RepeatableContainers {
static final Map<Class<? extends Annotation>, Object> cache = new ConcurrentReferenceHashMap<>();
@Nullable
private final RepeatableContainers parent;
@@ -139,6 +137,8 @@ public abstract class RepeatableContainers {
*/
private static class StandardRepeatableContainers extends RepeatableContainers {
private static final Map<Class<? extends Annotation>, Object> cache = new ConcurrentReferenceHashMap<>();
private static final Object NONE = new Object();
private static StandardRepeatableContainers INSTANCE = new StandardRepeatableContainers();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -205,7 +205,8 @@ public class GenericConversionService implements ConfigurableConversionService {
* @param targetType the target type
* @return the converted value
* @throws ConversionException if a conversion exception occurred
* @throws IllegalArgumentException if targetType is {@code null}
* @throws IllegalArgumentException if targetType is {@code null},
* or sourceType is {@code null} but source is not {@code null}
*/
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor targetType) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -252,7 +252,7 @@ public abstract class CommandLinePropertySource<T> extends EnumerablePropertySou
@Override
public final boolean containsProperty(String name) {
if (this.nonOptionArgsPropertyName.equals(name)) {
return !getNonOptionArgs().isEmpty();
return !this.getNonOptionArgs().isEmpty();
}
return this.containsOption(name);
}
@@ -270,7 +270,7 @@ public abstract class CommandLinePropertySource<T> extends EnumerablePropertySou
@Nullable
public final String getProperty(String name) {
if (this.nonOptionArgsPropertyName.equals(name)) {
Collection<String> nonOptionArguments = getNonOptionArgs();
Collection<String> nonOptionArguments = this.getNonOptionArgs();
if (nonOptionArguments.isEmpty()) {
return null;
}
@@ -278,7 +278,7 @@ public abstract class CommandLinePropertySource<T> extends EnumerablePropertySou
return StringUtils.collectionToCommaDelimitedString(nonOptionArguments);
}
}
Collection<String> optionValues = getOptionValues(name);
Collection<String> optionValues = this.getOptionValues(name);
if (optionValues == null) {
return null;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -96,25 +96,6 @@ public interface Environment extends PropertyResolver {
*/
String[] getDefaultProfiles();
/**
* Determine whether one of the given profile expressions matches the
* {@linkplain #getActiveProfiles() active profiles} &mdash; or in the case
* of no explicit active profiles, whether one of the given profile expressions
* matches the {@linkplain #getDefaultProfiles() default profiles}.
* <p>Profile expressions allow for complex, boolean profile logic to be
* expressed &mdash; for example {@code "p1 & p2"}, {@code "(p1 & p2) | p3"},
* etc. See {@link Profiles#of(String...)} for details on the supported
* expression syntax.
* <p>This method is a convenient shortcut for
* {@code env.acceptsProfiles(Profiles.of(profileExpressions))}.
* @since 5.3.28
* @see Profiles#of(String...)
* @see #acceptsProfiles(Profiles)
*/
default boolean matchesProfiles(String... profileExpressions) {
return acceptsProfiles(Profiles.of(profileExpressions));
}
/**
* Determine whether one or more of the given profiles is active &mdash; or
* in the case of no explicit {@linkplain #getActiveProfiles() active profiles},
@@ -137,6 +118,25 @@ public interface Environment extends PropertyResolver {
@Deprecated
boolean acceptsProfiles(String... profiles);
/**
* Determine whether one of the given profile expressions matches the
* {@linkplain #getActiveProfiles() active profiles} &mdash; or in the case
* of no explicit active profiles, whether one of the given profile expressions
* matches the {@linkplain #getDefaultProfiles() default profiles}.
* <p>Profile expressions allow for complex, boolean profile logic to be
* expressed &mdash; for example {@code "p1 & p2"}, {@code "(p1 & p2) | p3"},
* etc. See {@link Profiles#of(String...)} for details on the supported
* expression syntax.
* <p>This method is a convenient shortcut for
* {@code env.acceptsProfiles(Profiles.of(profileExpressions))}.
* @since 5.3.28
* @see Profiles#of(String...)
* @see #acceptsProfiles(Profiles)
*/
default boolean matchesProfiles(String... profileExpressions) {
return acceptsProfiles(Profiles.of(profileExpressions));
}
/**
* Determine whether the given {@link Profiles} predicate matches the
* {@linkplain #getActiveProfiles() active profiles} &mdash; or in the case
@@ -168,27 +168,31 @@ final class ProfilesParser {
return false;
}
@Override
public int hashCode() {
return this.expressions.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ParsedProfiles that = (ParsedProfiles) obj;
return this.expressions.equals(that.expressions);
}
@Override
public int hashCode() {
return this.expressions.hashCode();
}
@Override
public String toString() {
return StringUtils.collectionToDelimitedString(this.expressions, " or ");
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -33,15 +33,13 @@ import org.springframework.util.StringUtils;
*
* <p>Supports resolution as {@code java.io.File} if the class path
* resource resides in the file system, but not for resources in a JAR.
* Always supports resolution as {@code java.net.URL}.
* Always supports resolution as URL.
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 28.12.2003
* @see ClassLoader#getResourceAsStream(String)
* @see ClassLoader#getResource(String)
* @see Class#getResourceAsStream(String)
* @see Class#getResource(String)
*/
public class ClassPathResource extends AbstractFileResolvingResource {
@@ -126,7 +124,7 @@ public class ClassPathResource extends AbstractFileResolvingResource {
}
/**
* Return the {@link ClassLoader} that this resource will be obtained from.
* Return the ClassLoader that this resource will be obtained from.
*/
@Nullable
public final ClassLoader getClassLoader() {
@@ -136,8 +134,8 @@ public class ClassPathResource extends AbstractFileResolvingResource {
/**
* This implementation checks for the resolution of a resource URL.
* @see ClassLoader#getResource(String)
* @see Class#getResource(String)
* @see java.lang.ClassLoader#getResource(String)
* @see java.lang.Class#getResource(String)
*/
@Override
public boolean exists() {
@@ -147,8 +145,8 @@ public class ClassPathResource extends AbstractFileResolvingResource {
/**
* This implementation checks for the resolution of a resource URL upfront,
* then proceeding with {@link AbstractFileResolvingResource}'s length check.
* @see ClassLoader#getResource(String)
* @see Class#getResource(String)
* @see java.lang.ClassLoader#getResource(String)
* @see java.lang.Class#getResource(String)
*/
@Override
public boolean isReadable() {
@@ -181,11 +179,9 @@ public class ClassPathResource extends AbstractFileResolvingResource {
}
/**
* This implementation opens an {@link InputStream} for the underlying class
* path resource, if available.
* @see ClassLoader#getResourceAsStream(String)
* @see Class#getResourceAsStream(String)
* @see ClassLoader#getSystemResourceAsStream(String)
* This implementation opens an InputStream for the given class path resource.
* @see java.lang.ClassLoader#getResourceAsStream(String)
* @see java.lang.Class#getResourceAsStream(String)
*/
@Override
public InputStream getInputStream() throws IOException {
@@ -208,8 +204,8 @@ public class ClassPathResource extends AbstractFileResolvingResource {
/**
* This implementation returns a URL for the underlying class path resource,
* if available.
* @see ClassLoader#getResource(String)
* @see Class#getResource(String)
* @see java.lang.ClassLoader#getResource(String)
* @see java.lang.Class#getResource(String)
*/
@Override
public URL getURL() throws IOException {
@@ -221,9 +217,9 @@ public class ClassPathResource extends AbstractFileResolvingResource {
}
/**
* This implementation creates a {@code ClassPathResource}, applying the given
* path relative to the path used to create this descriptor.
* @see StringUtils#applyRelativePath(String, String)
* This implementation creates a ClassPathResource, applying the given path
* relative to the path of the underlying resource of this descriptor.
* @see org.springframework.util.StringUtils#applyRelativePath(String, String)
*/
@Override
public Resource createRelative(String relativePath) {
@@ -235,7 +231,7 @@ public class ClassPathResource extends AbstractFileResolvingResource {
/**
* This implementation returns the name of the file that this class path
* resource refers to.
* @see StringUtils#getFilename(String)
* @see org.springframework.util.StringUtils#getFilename(String)
*/
@Override
@Nullable
@@ -281,7 +277,8 @@ public class ClassPathResource extends AbstractFileResolvingResource {
}
/**
* This implementation returns the hash code of the underlying class path location.
* This implementation returns the hash code of the underlying
* class path location.
*/
@Override
public int hashCode() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -158,7 +158,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
/**
* This implementation returns whether the underlying file exists.
* @see java.io.File#exists()
* @see java.nio.file.Files#exists(Path, java.nio.file.LinkOption...)
*/
@Override
public boolean exists() {
@@ -170,8 +169,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
* (and corresponds to an actual file with content, not to a directory).
* @see java.io.File#canRead()
* @see java.io.File#isDirectory()
* @see java.nio.file.Files#isReadable(Path)
* @see java.nio.file.Files#isDirectory(Path, java.nio.file.LinkOption...)
*/
@Override
public boolean isReadable() {
@@ -180,8 +177,8 @@ public class FileSystemResource extends AbstractResource implements WritableReso
}
/**
* This implementation opens an NIO file stream for the underlying file.
* @see java.nio.file.Files#newInputStream(Path, java.nio.file.OpenOption...)
* This implementation opens a NIO file stream for the underlying file.
* @see java.io.FileInputStream
*/
@Override
public InputStream getInputStream() throws IOException {
@@ -198,8 +195,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
* (and corresponds to an actual file with content, not to a directory).
* @see java.io.File#canWrite()
* @see java.io.File#isDirectory()
* @see java.nio.file.Files#isWritable(Path)
* @see java.nio.file.Files#isDirectory(Path, java.nio.file.LinkOption...)
*/
@Override
public boolean isWritable() {
@@ -209,7 +204,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
/**
* This implementation opens a FileOutputStream for the underlying file.
* @see java.nio.file.Files#newOutputStream(Path, java.nio.file.OpenOption...)
* @see java.io.FileOutputStream
*/
@Override
public OutputStream getOutputStream() throws IOException {
@@ -219,7 +214,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
/**
* This implementation returns a URL for the underlying file.
* @see java.io.File#toURI()
* @see java.nio.file.Path#toUri()
*/
@Override
public URL getURL() throws IOException {
@@ -229,7 +223,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
/**
* This implementation returns a URI for the underlying file.
* @see java.io.File#toURI()
* @see java.nio.file.Path#toUri()
*/
@Override
public URI getURI() throws IOException {
@@ -331,7 +324,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
/**
* This implementation returns the name of the file.
* @see java.io.File#getName()
* @see java.nio.file.Path#getFileName()
*/
@Override
public String getFilename() {
@@ -342,7 +334,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
* This implementation returns a description that includes the absolute
* path of the file.
* @see java.io.File#getAbsolutePath()
* @see java.nio.file.Path#toAbsolutePath()
*/
@Override
public String getDescription() {
@@ -351,7 +342,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
/**
* This implementation compares the underlying file paths.
* This implementation compares the underlying File references.
*/
@Override
public boolean equals(@Nullable Object other) {
@@ -360,7 +351,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
}
/**
* This implementation returns the hash code of the underlying file path.
* This implementation returns the hash code of the underlying File reference.
*/
@Override
public int hashCode() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -61,7 +61,7 @@ public class PathResource extends AbstractResource implements WritableResource {
/**
* Create a new {@code PathResource} from a {@link Path} handle.
* Create a new PathResource from a Path handle.
* <p>Note: Unlike {@link FileSystemResource}, when building relative resources
* via {@link #createRelative}, the relative path will be built <i>underneath</i>
* the given root: e.g. Paths.get("C:/dir1/"), relative path "dir2" &rarr; "C:/dir1/dir2"!
@@ -73,7 +73,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* Create a new {@code PathResource} from a path string.
* Create a new PathResource from a Path handle.
* <p>Note: Unlike {@link FileSystemResource}, when building relative resources
* via {@link #createRelative}, the relative path will be built <i>underneath</i>
* the given root: e.g. Paths.get("C:/dir1/"), relative path "dir2" &rarr; "C:/dir1/dir2"!
@@ -86,7 +86,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* Create a new {@code PathResource} from a {@link URI}.
* Create a new PathResource from a Path handle.
* <p>Note: Unlike {@link FileSystemResource}, when building relative resources
* via {@link #createRelative}, the relative path will be built <i>underneath</i>
* the given root: e.g. Paths.get("C:/dir1/"), relative path "dir2" &rarr; "C:/dir1/dir2"!
@@ -127,7 +127,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation opens an {@link InputStream} for the underlying file.
* This implementation opens a InputStream for the underlying file.
* @see java.nio.file.spi.FileSystemProvider#newInputStream(Path, OpenOption...)
*/
@Override
@@ -153,7 +153,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation opens an {@link OutputStream} for the underlying file.
* This implementation opens a OutputStream for the underlying file.
* @see java.nio.file.spi.FileSystemProvider#newOutputStream(Path, OpenOption...)
*/
@Override
@@ -165,7 +165,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation returns a {@link URL} for the underlying file.
* This implementation returns a URL for the underlying file.
* @see java.nio.file.Path#toUri()
* @see java.net.URI#toURL()
*/
@@ -175,7 +175,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation returns a {@link URI} for the underlying file.
* This implementation returns a URI for the underlying file.
* @see java.nio.file.Path#toUri()
*/
@Override
@@ -192,7 +192,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation returns the underlying {@link File} reference.
* This implementation returns the underlying File reference.
*/
@Override
public File getFile() throws IOException {
@@ -207,7 +207,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation opens a {@link ReadableByteChannel} for the underlying file.
* This implementation opens a Channel for the underlying file.
* @see Files#newByteChannel(Path, OpenOption...)
*/
@Override
@@ -221,7 +221,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation opens a {@link WritableByteChannel} for the underlying file.
* This implementation opens a Channel for the underlying file.
* @see Files#newByteChannel(Path, OpenOption...)
*/
@Override
@@ -238,7 +238,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation returns the underlying file's timestamp.
* This implementation returns the underlying File's timestamp.
* @see java.nio.file.Files#getLastModifiedTime(Path, java.nio.file.LinkOption...)
*/
@Override
@@ -249,7 +249,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation creates a {@link PathResource}, applying the given path
* This implementation creates a PathResource, applying the given path
* relative to the path of the underlying file of this resource descriptor.
* @see java.nio.file.Path#resolve(String)
*/
@@ -274,7 +274,7 @@ public class PathResource extends AbstractResource implements WritableResource {
/**
* This implementation compares the underlying {@link Path} references.
* This implementation compares the underlying Path references.
*/
@Override
public boolean equals(@Nullable Object other) {
@@ -283,7 +283,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation returns the hash code of the underlying {@link Path} reference.
* This implementation returns the hash code of the underlying Path reference.
*/
@Override
public int hashCode() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* 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.
@@ -33,8 +33,8 @@ import org.springframework.util.concurrent.ListenableFutureTask;
* {@link TaskExecutor} implementation that fires up a new Thread for each task,
* executing it asynchronously.
*
* <p>Supports limiting concurrent threads through {@link #setConcurrencyLimit}.
* By default, the number of concurrent task executions is unlimited.
* <p>Supports limiting concurrent threads through the "concurrencyLimit"
* bean property. By default, the number of concurrent threads is unlimited.
*
* <p><b>NOTE: This implementation does not reuse threads!</b> Consider a
* thread-pooling TaskExecutor implementation instead, in particular for
@@ -133,31 +133,33 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator
* have to cast it and call {@code Future#get} to evaluate exceptions.
* @since 4.3
*/
public void setTaskDecorator(TaskDecorator taskDecorator) {
public final void setTaskDecorator(TaskDecorator taskDecorator) {
this.taskDecorator = taskDecorator;
}
/**
* Set the maximum number of parallel task executions allowed.
* The default of -1 indicates no concurrency limit at all.
* <p>This is the equivalent of a maximum pool size in a thread pool,
* preventing temporary overload of the thread management system.
* Set the maximum number of parallel accesses allowed.
* -1 indicates no concurrency limit at all.
* <p>In principle, this limit can be changed at runtime,
* although it is generally designed as a config time setting.
* NOTE: Do not switch between -1 and any concrete limit at runtime,
* as this will lead to inconsistent concurrency counts: A limit
* of -1 effectively turns off concurrency counting completely.
* @see #UNBOUNDED_CONCURRENCY
* @see org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor#setMaxPoolSize
*/
public void setConcurrencyLimit(int concurrencyLimit) {
this.concurrencyThrottle.setConcurrencyLimit(concurrencyLimit);
}
/**
* Return the maximum number of parallel task executions allowed.
* Return the maximum number of parallel accesses allowed.
*/
public final int getConcurrencyLimit() {
return this.concurrencyThrottle.getConcurrencyLimit();
}
/**
* Return whether the concurrency throttle is currently active.
* Return whether this throttle is currently active.
* @return {@code true} if the concurrency limit for this instance is active
* @see #getConcurrencyLimit()
* @see #setConcurrencyLimit
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -171,7 +171,6 @@ final class SimpleAnnotationMetadataReadingVisitor extends ClassVisitor {
return (access & Opcodes.ACC_INTERFACE) != 0;
}
/**
* {@link MergedAnnotation} source.
*/
@@ -183,6 +182,11 @@ final class SimpleAnnotationMetadataReadingVisitor extends ClassVisitor {
this.className = className;
}
@Override
public int hashCode() {
return this.className.hashCode();
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
@@ -194,15 +198,11 @@ final class SimpleAnnotationMetadataReadingVisitor extends ClassVisitor {
return this.className.equals(((Source) obj).className);
}
@Override
public int hashCode() {
return this.className.hashCode();
}
@Override
public String toString() {
return this.className;
}
}
}
@@ -50,7 +50,6 @@ import org.springframework.lang.Nullable;
* @author Keith Donald
* @author Rob Harrop
* @author Sam Brannen
* @author Sebastien Deleuze
* @since 1.1
* @see TypeUtils
* @see ReflectionUtils
@@ -84,12 +83,6 @@ public abstract class ClassUtils {
/** The ".class" file suffix. */
public static final String CLASS_FILE_SUFFIX = ".class";
/** Precomputed value for the combination of private, static and final modifiers. */
private static final int NON_OVERRIDABLE_MODIFIER = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
/** Precomputed value for the combination of public and protected modifiers. */
private static final int OVERRIDABLE_MODIFIER = Modifier.PUBLIC | Modifier.PROTECTED;
/**
* Map with primitive wrapper type as key and corresponding primitive
@@ -1386,10 +1379,10 @@ public abstract class ClassUtils {
* @param targetClass the target class to check against
*/
private static boolean isOverridable(Method method, @Nullable Class<?> targetClass) {
if ((method.getModifiers() & NON_OVERRIDABLE_MODIFIER) != 0) {
if (Modifier.isPrivate(method.getModifiers())) {
return false;
}
if ((method.getModifiers() & OVERRIDABLE_MODIFIER) != 0) {
if (Modifier.isPublic(method.getModifiers()) || Modifier.isProtected(method.getModifiers())) {
return true;
}
return (targetClass == null ||
@@ -1410,7 +1403,7 @@ public abstract class ClassUtils {
Assert.notNull(methodName, "Method name must not be null");
try {
Method method = clazz.getMethod(methodName, args);
return (Modifier.isStatic(method.getModifiers()) ? method : null);
return Modifier.isStatic(method.getModifiers()) ? method : null;
}
catch (NoSuchMethodException ex) {
return null;

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