Compare commits

..

1 Commits

Author SHA1 Message Date
Spring Builds 13b31c7976 Release v5.3.29 2023-07-13 07:44:31 +00:00
156 changed files with 1281 additions and 1910 deletions
+1 -1
View File
@@ -28,7 +28,7 @@ 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.netty:netty-bom:4.1.94.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.34"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR13"
mavenBom "io.rsocket:rsocket-bom:1.1.3"
+1 -1
View File
@@ -1,4 +1,4 @@
version=5.3.30
version=5.3.29
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.
*/
@@ -702,7 +651,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;
@@ -721,7 +670,8 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
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;
@@ -804,7 +754,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 +763,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;
@@ -828,16 +778,16 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
if (!this.cached) {
if (arguments != null) {
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, argumentCount);
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == argumentCount) {
Iterator<String> it = autowiredBeanNames.iterator();
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]);
}
}
}
@@ -863,14 +813,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-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
@@ -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
@@ -72,9 +72,6 @@ import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.Order;
import org.springframework.core.testfixture.io.SerializationTestUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import static org.assertj.core.api.Assertions.assertThat;
@@ -134,8 +131,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bean = bf.getBean("annotatedBean", ResourceInjectionBean.class);
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(new String[] {"testBean"});
}
@Test
@@ -157,12 +152,10 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(new String[] {"testBean"});
}
@Test
void resourceInjectionWithSometimesNullBeanEarly() {
void resourceInjectionWithSometimesNullBean() {
RootBeanDefinition bd = new RootBeanDefinition(OptionalResourceInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
@@ -177,55 +170,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
SometimesNullFactoryMethods.active = false;
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
SometimesNullFactoryMethods.active = true;
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNotNull();
assertThat(bean.getTestBean2()).isNotNull();
assertThat(bean.getTestBean3()).isNotNull();
SometimesNullFactoryMethods.active = true;
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNotNull();
assertThat(bean.getTestBean2()).isNotNull();
assertThat(bean.getTestBean3()).isNotNull();
SometimesNullFactoryMethods.active = false;
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
SometimesNullFactoryMethods.active = false;
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(new String[] {"testBean"});
}
@Test
void resourceInjectionWithSometimesNullBeanLate() {
RootBeanDefinition bd = new RootBeanDefinition(OptionalResourceInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
RootBeanDefinition tb = new RootBeanDefinition(SometimesNullFactoryMethods.class);
tb.setFactoryMethodName("createTestBean");
tb.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("testBean", tb);
SometimesNullFactoryMethods.active = true;
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNotNull();
assertThat(bean.getTestBean2()).isNotNull();
assertThat(bean.getTestBean3()).isNotNull();
SometimesNullFactoryMethods.active = true;
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNotNull();
@@ -250,13 +194,17 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getTestBean2()).isNotNull();
assertThat(bean.getTestBean3()).isNotNull();
SometimesNullFactoryMethods.active = true;
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNotNull();
assertThat(bean.getTestBean2()).isNotNull();
assertThat(bean.getTestBean3()).isNotNull();
SometimesNullFactoryMethods.active = false;
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(new String[] {"testBean"});
}
@Test
@@ -285,7 +233,10 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
assertThat(bean.getBeanFactory()).isSameAs(bf);
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(new String[] {"testBean", "nestedTestBean"});
String[] depBeans = bf.getDependenciesForBean("annotatedBean");
assertThat(depBeans.length).isEqualTo(2);
assertThat(depBeans[0]).isEqualTo("testBean");
assertThat(depBeans[1]).isEqualTo("nestedTestBean");
}
@Test
@@ -447,22 +398,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
bf.destroySingleton("testBean");
bf.registerSingleton("testBeanX", tb);
bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
assertThat(bean.getNestedTestBeans()).hasSize(2);
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
assertThat(bean.nestedTestBeansField).hasSize(2);
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
bf.destroySingleton("testBeanX");
bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
assertThat(bean.getTestBean()).isNull();
@@ -520,22 +455,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
bf.removeBeanDefinition("testBean");
bf.registerBeanDefinition("testBeanX", new RootBeanDefinition(TestBean.class));
bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBeanX"));
assertThat(bean.getTestBean2()).isSameAs(bf.getBean("testBeanX"));
assertThat(bean.getTestBean3()).isSameAs(bf.getBean("testBeanX"));
assertThat(bean.getTestBean4()).isSameAs(bf.getBean("testBeanX"));
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
assertThat(bean.getNestedTestBeans()).hasSize(2);
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
assertThat(bean.nestedTestBeansField).hasSize(2);
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
bf.removeBeanDefinition("testBeanX");
bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
assertThat(bean.getTestBean()).isNull();
@@ -800,9 +719,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
assertThat(bean.getBeanFactory()).isSameAs(bf);
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(
new String[] {"testBean", "nestedTestBean", ObjectUtils.identityToString(bf)});
}
@Test
@@ -824,17 +740,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getBeanFactory()).isSameAs(bf);
bf.destroySingleton("nestedTestBean");
bf.registerSingleton("nestedTestBeanX", ntb);
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
assertThat(bean.getBeanFactory()).isSameAs(bf);
bf.destroySingleton("nestedTestBeanX");
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
assertThat(bean.getTestBean()).isSameAs(tb);
@@ -873,17 +778,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getBeanFactory()).isSameAs(bf);
bf.removeBeanDefinition("nestedTestBean");
bf.registerBeanDefinition("nestedTestBeanX", new RootBeanDefinition(NestedTestBean.class));
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getNestedTestBean()).isSameAs(bf.getBean("nestedTestBeanX"));
assertThat(bean.getBeanFactory()).isSameAs(bf);
bf.removeBeanDefinition("nestedTestBeanX");
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
assertThat(bean.getTestBean()).isSameAs(tb);
@@ -987,80 +881,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
.satisfies(methodParameterDeclaredOn(ConstructorWithoutFallbackBean.class));
}
@Test
void constructorResourceInjectionWithSometimesNullBeanEarly() {
RootBeanDefinition bd = new RootBeanDefinition(ConstructorWithNullableArgument.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
RootBeanDefinition tb = new RootBeanDefinition(SometimesNullFactoryMethods.class);
tb.setFactoryMethodName("createTestBean");
tb.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("testBean", tb);
SometimesNullFactoryMethods.active = false;
ConstructorWithNullableArgument bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNull();
SometimesNullFactoryMethods.active = false;
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNull();
SometimesNullFactoryMethods.active = true;
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNotNull();
SometimesNullFactoryMethods.active = true;
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNotNull();
SometimesNullFactoryMethods.active = false;
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNull();
SometimesNullFactoryMethods.active = false;
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNull();
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(new String[] {"testBean"});
}
@Test
void constructorResourceInjectionWithSometimesNullBeanLate() {
RootBeanDefinition bd = new RootBeanDefinition(ConstructorWithNullableArgument.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
RootBeanDefinition tb = new RootBeanDefinition(SometimesNullFactoryMethods.class);
tb.setFactoryMethodName("createTestBean");
tb.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("testBean", tb);
SometimesNullFactoryMethods.active = true;
ConstructorWithNullableArgument bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNotNull();
SometimesNullFactoryMethods.active = true;
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNotNull();
SometimesNullFactoryMethods.active = false;
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNull();
SometimesNullFactoryMethods.active = false;
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNull();
SometimesNullFactoryMethods.active = true;
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNotNull();
SometimesNullFactoryMethods.active = false;
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNull();
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(new String[] {"testBean"});
}
@Test
public void testConstructorResourceInjectionWithCollectionAndNullFromFactoryBean() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(
@@ -2621,12 +2441,13 @@ public class AutowiredAnnotationBeanPostProcessorTests {
@Autowired(required = false)
private TestBean testBean;
TestBean testBean2;
private TestBean testBean2;
@Autowired
public void setTestBean2(TestBean testBean2) {
Assert.state(this.testBean != null, "Wrong initialization order");
Assert.state(this.testBean2 == null, "Already called");
if (this.testBean2 != null) {
throw new IllegalStateException("Already called");
}
this.testBean2 = testBean2;
}
@@ -2661,7 +2482,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
@Required
@SuppressWarnings("deprecation")
public void setTestBean2(TestBean testBean2) {
this.testBean2 = testBean2;
super.setTestBean2(testBean2);
}
@Autowired
@@ -2677,7 +2498,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
@Autowired
protected void initBeanFactory(BeanFactory beanFactory) {
Assert.state(this.baseInjected, "Wrong initialization order");
this.beanFactory = beanFactory;
}
@@ -2984,21 +2804,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
}
public static class ConstructorWithNullableArgument {
protected ITestBean testBean3;
@Autowired(required = false)
public ConstructorWithNullableArgument(@Nullable ITestBean testBean3) {
this.testBean3 = testBean3;
}
public ITestBean getTestBean3() {
return this.testBean3;
}
}
public static class ConstructorsCollectionResourceInjectionBean {
protected ITestBean testBean3;
@@ -4101,7 +3906,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
private RT obj;
protected void setObj(RT obj) {
Assert.state(this.obj == null, "Already called");
if (this.obj != null) {
throw new IllegalStateException("Already called");
}
this.obj = obj;
}
}
@@ -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) {
@@ -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-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-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() {
@@ -1083,9 +1083,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);
@@ -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);
@@ -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);
@@ -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-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 {
@@ -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,7 +207,6 @@ 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());
@@ -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.
@@ -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-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.
@@ -63,7 +63,7 @@ public class EnableSchedulingTests {
ctx = new AnnotationConfigApplicationContext(FixedRateTaskConfig.class);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(2);
Thread.sleep(110);
Thread.sleep(100);
assertThat(ctx.getBean(AtomicInteger.class).get()).isGreaterThanOrEqualTo(10);
}
@@ -73,7 +73,7 @@ public class EnableSchedulingTests {
ctx = new AnnotationConfigApplicationContext(FixedRateTaskConfigSubclass.class);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(2);
Thread.sleep(110);
Thread.sleep(100);
assertThat(ctx.getBean(AtomicInteger.class).get()).isGreaterThanOrEqualTo(10);
}
@@ -83,7 +83,7 @@ public class EnableSchedulingTests {
ctx = new AnnotationConfigApplicationContext(ExplicitSchedulerConfig.class);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(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(
@@ -102,7 +102,7 @@ public class EnableSchedulingTests {
ctx = new AnnotationConfigApplicationContext(ExplicitScheduledTaskRegistrarConfig.class);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(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.
@@ -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();
@@ -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-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.
@@ -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;
}
@@ -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-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;
@@ -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.
@@ -69,7 +69,7 @@ public abstract class ConcurrencyThrottleSupport implements Serializable {
/**
* Set the maximum number of concurrent access attempts allowed.
* The default of -1 indicates no concurrency limit at all.
* -1 indicates unbounded concurrency.
* <p>In principle, this limit can be changed at runtime,
* although it is generally designed as a config time setting.
* <p>NOTE: Do not switch between -1 and any concrete limit at runtime,
@@ -143,10 +143,9 @@ public abstract class ConcurrencyThrottleSupport implements Serializable {
*/
protected void afterAccess() {
if (this.concurrencyLimit >= 0) {
boolean debug = logger.isDebugEnabled();
synchronized (this.monitor) {
this.concurrencyCount--;
if (debug) {
if (logger.isDebugEnabled()) {
logger.debug("Returning from throttle at concurrency count " + this.concurrencyCount);
}
this.monitor.notify();
@@ -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.
@@ -752,27 +752,28 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
}
@Override
public boolean equals(@Nullable Object other) {
public String toString() {
return (this.key + "=" + this.value);
}
@Override
@SuppressWarnings("rawtypes")
public final boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof Map.Entry<?, ?>)) {
if (!(other instanceof Map.Entry)) {
return false;
}
Map.Entry<?, ?> otherEntry = (Map.Entry<?, ?>) other;
Map.Entry otherEntry = (Map.Entry) other;
return (ObjectUtils.nullSafeEquals(getKey(), otherEntry.getKey()) &&
ObjectUtils.nullSafeEquals(getValue(), otherEntry.getValue()));
}
@Override
public int hashCode() {
public final int hashCode() {
return (ObjectUtils.nullSafeHashCode(this.key) ^ ObjectUtils.nullSafeHashCode(this.value));
}
@Override
public String toString() {
return (this.key + "=" + this.value);
}
}
@@ -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.
@@ -123,8 +123,8 @@ public class MethodInvoker {
/**
* Set a fully qualified static method name to invoke,
* e.g. "example.MyExampleClass.myExampleMethod". This is a
* convenient alternative to specifying targetClass and targetMethod.
* e.g. "example.MyExampleClass.myExampleMethod".
* Convenient alternative to specifying targetClass and targetMethod.
* @see #setTargetClass
* @see #setTargetMethod
*/
@@ -157,16 +157,14 @@ public class MethodInvoker {
public void prepare() throws ClassNotFoundException, NoSuchMethodException {
if (this.staticMethod != null) {
int lastDotIndex = this.staticMethod.lastIndexOf('.');
if (lastDotIndex == -1 || lastDotIndex == this.staticMethod.length() - 1) {
if (lastDotIndex == -1 || lastDotIndex == this.staticMethod.length()) {
throw new IllegalArgumentException(
"staticMethod must be a fully qualified class plus method name: " +
"e.g. 'example.MyExampleClass.myExampleMethod'");
}
String className = this.staticMethod.substring(0, lastDotIndex);
String methodName = this.staticMethod.substring(lastDotIndex + 1);
if (this.targetClass == null || !this.targetClass.getName().equals(className)) {
this.targetClass = resolveClassName(className);
}
this.targetClass = resolveClassName(className);
this.targetMethod = methodName;
}
@@ -70,8 +70,8 @@ public abstract class ObjectUtils {
private static final String ARRAY_ELEMENT_SEPARATOR = ", ";
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
private static final String NON_EMPTY_ARRAY = ARRAY_START + "..." + ARRAY_END;
private static final String COLLECTION = "[...]";
private static final String MAP = NON_EMPTY_ARRAY;
private static final String EMPTY_COLLECTION = "[]";
private static final String NON_EMPTY_COLLECTION = "[...]";
/**
@@ -938,9 +938,10 @@ public abstract class ObjectUtils {
* <li>{@code"Optional[<concise-string>]"} if {@code obj} is a non-empty {@code Optional},
* where {@code <concise-string>} is the result of invoking {@link #nullSafeConciseToString}
* on the object contained in the {@code Optional}</li>
* <li>{@code "{}"} if {@code obj} is an empty array</li>
* <li>{@code "{...}"} if {@code obj} is a {@link Map} or a non-empty array</li>
* <li>{@code "[...]"} if {@code obj} is a {@link Collection}</li>
* <li>{@code "{}"} if {@code obj} is an empty array or {@link Map}</li>
* <li>{@code "{...}"} if {@code obj} is a non-empty array or {@link Map}</li>
* <li>{@code "[]"} if {@code obj} is an empty {@link Collection}</li>
* <li>{@code "[...]"} if {@code obj} is a non-empty {@link Collection}</li>
* <li>{@linkplain Class#getName() Class name} if {@code obj} is a {@link Class}</li>
* <li>{@linkplain Charset#name() Charset name} if {@code obj} is a {@link Charset}</li>
* <li>{@linkplain TimeZone#getID() TimeZone ID} if {@code obj} is a {@link TimeZone}</li>
@@ -976,11 +977,12 @@ public abstract class ObjectUtils {
if (obj.getClass().isArray()) {
return (Array.getLength(obj) == 0 ? EMPTY_ARRAY : NON_EMPTY_ARRAY);
}
if (obj instanceof Collection) {
return COLLECTION;
if (obj instanceof Collection<?>) {
return (((Collection<?>) obj).isEmpty() ? EMPTY_COLLECTION : NON_EMPTY_COLLECTION);
}
if (obj instanceof Map) {
return MAP;
if (obj instanceof Map<?, ?>) {
// EMPTY_ARRAY and NON_EMPTY_ARRAY are also used for maps.
return (((Map<?, ?>) obj).isEmpty() ? EMPTY_ARRAY : NON_EMPTY_ARRAY);
}
if (obj instanceof Class<?>) {
return ((Class<?>) obj).getName();
@@ -247,26 +247,26 @@ public abstract class StringUtils {
/**
* Trim <em>all</em> whitespace from the given {@code CharSequence}:
* leading, trailing, and in between characters.
* @param str the {@code CharSequence} to check
* @param text the {@code CharSequence} to check
* @return the trimmed {@code CharSequence}
* @since 5.3.22
* @see #trimAllWhitespace(String)
* @see java.lang.Character#isWhitespace
*/
public static CharSequence trimAllWhitespace(CharSequence str) {
if (!hasLength(str)) {
return str;
public static CharSequence trimAllWhitespace(CharSequence text) {
if (!hasLength(text)) {
return text;
}
int len = str.length();
StringBuilder sb = new StringBuilder(str.length());
int len = text.length();
StringBuilder sb = new StringBuilder(text.length());
for (int i = 0; i < len; i++) {
char c = str.charAt(i);
char c = text.charAt(i);
if (!Character.isWhitespace(c)) {
sb.append(c);
}
}
return sb;
return sb.toString();
}
/**
@@ -278,10 +278,9 @@ public abstract class StringUtils {
* @see java.lang.Character#isWhitespace
*/
public static String trimAllWhitespace(String str) {
if (!hasLength(str)) {
return str;
if (str == null) {
return null;
}
return trimAllWhitespace((CharSequence) str).toString();
}
@@ -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.
@@ -85,7 +85,7 @@ public class NullSafeComparator<T> implements Comparator<T> {
* @param nullsLow whether to treat nulls lower or higher than non-null objects
*/
public NullSafeComparator(Comparator<T> comparator, boolean nullsLow) {
Assert.notNull(comparator, "Comparator must not be null");
Assert.notNull(comparator, "Non-null Comparator is required");
this.nonNullComparator = comparator;
this.nullsLow = nullsLow;
}
@@ -107,16 +107,16 @@ public class NullSafeComparator<T> implements Comparator<T> {
@Override
@SuppressWarnings("unchecked")
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof NullSafeComparator<?>)) {
if (!(other instanceof NullSafeComparator)) {
return false;
}
NullSafeComparator<?> otherComp = (NullSafeComparator<?>) other;
return (this.nonNullComparator.equals(otherComp.nonNullComparator) &&
this.nullsLow == otherComp.nullsLow);
NullSafeComparator<T> otherComp = (NullSafeComparator<T>) other;
return (this.nonNullComparator.equals(otherComp.nonNullComparator) && this.nullsLow == otherComp.nullsLow);
}
@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.
@@ -37,7 +37,6 @@ import static org.assertj.core.api.Assertions.assertThat;
* Unit tests for {@link ReactiveAdapterRegistry}.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
*/
@SuppressWarnings("unchecked")
class ReactiveAdapterRegistryTests {
@@ -53,40 +52,14 @@ class ReactiveAdapterRegistryTests {
ReactiveAdapter adapter2 = getAdapter(ExtendedFlux.class);
assertThat(adapter2).isSameAs(adapter1);
// Register regular reactive type (after existing adapters)
this.registry.registerReactiveType(
ReactiveTypeDescriptor.multiValue(ExtendedFlux.class, ExtendedFlux::empty),
o -> (ExtendedFlux<?>) o,
ExtendedFlux::from);
// Matches for ExtendedFlux itself
ReactiveAdapter adapter3 = getAdapter(ExtendedFlux.class);
assertThat(adapter3).isNotNull();
assertThat(adapter3).isNotSameAs(adapter1);
// Does not match for ExtendedFlux subclass since the default Flux adapter
// is being assignability-checked first when no specific match was found
ReactiveAdapter adapter4 = getAdapter(ExtendedExtendedFlux.class);
assertThat(adapter4).isSameAs(adapter1);
// Register reactive type override (before existing adapters)
this.registry.registerReactiveTypeOverride(
ReactiveTypeDescriptor.multiValue(Flux.class, ExtendedFlux::empty),
o -> (ExtendedFlux<?>) o,
ExtendedFlux::from);
// Override match for Flux
ReactiveAdapter adapter5 = getAdapter(Flux.class);
assertThat(adapter5).isNotNull();
assertThat(adapter5).isNotSameAs(adapter1);
// Initially registered adapter specifically matches for ExtendedFlux
ReactiveAdapter adapter6 = getAdapter(ExtendedFlux.class);
assertThat(adapter6).isSameAs(adapter3);
// Override match for ExtendedFlux subclass
ReactiveAdapter adapter7 = getAdapter(ExtendedExtendedFlux.class);
assertThat(adapter7).isSameAs(adapter5);
}
@@ -106,10 +79,6 @@ class ReactiveAdapterRegistryTests {
}
private static class ExtendedExtendedFlux<T> extends ExtendedFlux<T> {
}
@Nested
class Reactor {
@@ -131,7 +100,7 @@ class ReactiveAdapterRegistryTests {
List<Integer> sequence = Arrays.asList(1, 2, 3);
Publisher<Integer> source = io.reactivex.rxjava3.core.Flowable.fromIterable(sequence);
Object target = getAdapter(Flux.class).fromPublisher(source);
assertThat(target).isInstanceOf(Flux.class);
assertThat(target instanceof Flux).isTrue();
assertThat(((Flux<Integer>) target).collectList().block(ONE_SECOND)).isEqualTo(sequence);
}
@@ -139,7 +108,7 @@ class ReactiveAdapterRegistryTests {
void toMono() {
Publisher<Integer> source = io.reactivex.rxjava3.core.Flowable.fromArray(1, 2, 3);
Object target = getAdapter(Mono.class).fromPublisher(source);
assertThat(target).isInstanceOf(Mono.class);
assertThat(target instanceof Mono).isTrue();
assertThat(((Mono<Integer>) target).block(ONE_SECOND)).isEqualTo(Integer.valueOf(1));
}
@@ -147,7 +116,7 @@ class ReactiveAdapterRegistryTests {
void toCompletableFuture() throws Exception {
Publisher<Integer> source = Flux.fromArray(new Integer[] {1, 2, 3});
Object target = getAdapter(CompletableFuture.class).fromPublisher(source);
assertThat(target).isInstanceOf(CompletableFuture.class);
assertThat(target instanceof CompletableFuture).isTrue();
assertThat(((CompletableFuture<Integer>) target).get()).isEqualTo(Integer.valueOf(1));
}
@@ -156,7 +125,7 @@ class ReactiveAdapterRegistryTests {
CompletableFuture<Integer> future = new CompletableFuture<>();
future.complete(1);
Object target = getAdapter(CompletableFuture.class).toPublisher(future);
assertThat(target).as("Expected Mono Publisher: " + target.getClass().getName()).isInstanceOf(Mono.class);
assertThat(target instanceof Mono).as("Expected Mono Publisher: " + target.getClass().getName()).isTrue();
assertThat(((Mono<Integer>) target).block(ONE_SECOND)).isEqualTo(Integer.valueOf(1));
}
}
@@ -325,7 +294,7 @@ class ReactiveAdapterRegistryTests {
List<Integer> sequence = Arrays.asList(1, 2, 3);
Publisher<Integer> source = Flux.fromIterable(sequence);
Object target = getAdapter(io.reactivex.rxjava3.core.Flowable.class).fromPublisher(source);
assertThat(target).isInstanceOf(io.reactivex.rxjava3.core.Flowable.class);
assertThat(target instanceof io.reactivex.rxjava3.core.Flowable).isTrue();
assertThat(((io.reactivex.rxjava3.core.Flowable<?>) target).toList().blockingGet()).isEqualTo(sequence);
}
@@ -334,7 +303,7 @@ class ReactiveAdapterRegistryTests {
List<Integer> sequence = Arrays.asList(1, 2, 3);
Publisher<Integer> source = Flux.fromIterable(sequence);
Object target = getAdapter(io.reactivex.rxjava3.core.Observable.class).fromPublisher(source);
assertThat(target).isInstanceOf(io.reactivex.rxjava3.core.Observable.class);
assertThat(target instanceof io.reactivex.rxjava3.core.Observable).isTrue();
assertThat(((io.reactivex.rxjava3.core.Observable<?>) target).toList().blockingGet()).isEqualTo(sequence);
}
@@ -342,7 +311,7 @@ class ReactiveAdapterRegistryTests {
void toSingle() {
Publisher<Integer> source = Flux.fromArray(new Integer[] {1});
Object target = getAdapter(io.reactivex.rxjava3.core.Single.class).fromPublisher(source);
assertThat(target).isInstanceOf(io.reactivex.rxjava3.core.Single.class);
assertThat(target instanceof io.reactivex.rxjava3.core.Single).isTrue();
assertThat(((io.reactivex.rxjava3.core.Single<Integer>) target).blockingGet()).isEqualTo(Integer.valueOf(1));
}
@@ -350,7 +319,7 @@ class ReactiveAdapterRegistryTests {
void toCompletable() {
Publisher<Integer> source = Flux.fromArray(new Integer[] {1, 2, 3});
Object target = getAdapter(io.reactivex.rxjava3.core.Completable.class).fromPublisher(source);
assertThat(target).isInstanceOf(io.reactivex.rxjava3.core.Completable.class);
assertThat(target instanceof io.reactivex.rxjava3.core.Completable).isTrue();
((io.reactivex.rxjava3.core.Completable) target).blockingAwait();
}
@@ -359,7 +328,7 @@ class ReactiveAdapterRegistryTests {
List<Integer> sequence = Arrays.asList(1, 2, 3);
Object source = io.reactivex.rxjava3.core.Flowable.fromIterable(sequence);
Object target = getAdapter(io.reactivex.rxjava3.core.Flowable.class).toPublisher(source);
assertThat(target).as("Expected Flux Publisher: " + target.getClass().getName()).isInstanceOf(Flux.class);
assertThat(target instanceof Flux).as("Expected Flux Publisher: " + target.getClass().getName()).isTrue();
assertThat(((Flux<Integer>) target).collectList().block(ONE_SECOND)).isEqualTo(sequence);
}
@@ -368,7 +337,7 @@ class ReactiveAdapterRegistryTests {
List<Integer> sequence = Arrays.asList(1, 2, 3);
Object source = io.reactivex.rxjava3.core.Observable.fromIterable(sequence);
Object target = getAdapter(io.reactivex.rxjava3.core.Observable.class).toPublisher(source);
assertThat(target).as("Expected Flux Publisher: " + target.getClass().getName()).isInstanceOf(Flux.class);
assertThat(target instanceof Flux).as("Expected Flux Publisher: " + target.getClass().getName()).isTrue();
assertThat(((Flux<Integer>) target).collectList().block(ONE_SECOND)).isEqualTo(sequence);
}
@@ -376,7 +345,7 @@ class ReactiveAdapterRegistryTests {
void fromSingle() {
Object source = io.reactivex.rxjava3.core.Single.just(1);
Object target = getAdapter(io.reactivex.rxjava3.core.Single.class).toPublisher(source);
assertThat(target).as("Expected Mono Publisher: " + target.getClass().getName()).isInstanceOf(Mono.class);
assertThat(target instanceof Mono).as("Expected Mono Publisher: " + target.getClass().getName()).isTrue();
assertThat(((Mono<Integer>) target).block(ONE_SECOND)).isEqualTo(Integer.valueOf(1));
}
@@ -384,7 +353,7 @@ class ReactiveAdapterRegistryTests {
void fromCompletable() {
Object source = io.reactivex.rxjava3.core.Completable.complete();
Object target = getAdapter(io.reactivex.rxjava3.core.Completable.class).toPublisher(source);
assertThat(target).as("Expected Mono Publisher: " + target.getClass().getName()).isInstanceOf(Mono.class);
assertThat(target instanceof Mono).as("Expected Mono Publisher: " + target.getClass().getName()).isTrue();
((Mono<Void>) target).block(ONE_SECOND);
}
}
@@ -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.
@@ -33,56 +33,57 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
class ByteBufferConverterTests {
private final GenericConversionService conversionService = new DefaultConversionService();
private GenericConversionService conversionService;
@BeforeEach
void setup() {
conversionService.addConverter(new ByteArrayToOtherTypeConverter());
conversionService.addConverter(new OtherTypeToByteArrayConverter());
this.conversionService = new DefaultConversionService();
this.conversionService.addConverter(new ByteArrayToOtherTypeConverter());
this.conversionService.addConverter(new OtherTypeToByteArrayConverter());
}
@Test
void byteArrayToByteBuffer() {
void byteArrayToByteBuffer() throws Exception {
byte[] bytes = new byte[] { 1, 2, 3 };
ByteBuffer convert = conversionService.convert(bytes, ByteBuffer.class);
ByteBuffer convert = this.conversionService.convert(bytes, ByteBuffer.class);
assertThat(convert.array()).isNotSameAs(bytes);
assertThat(convert.array()).isEqualTo(bytes);
}
@Test
void byteBufferToByteArray() {
void byteBufferToByteArray() throws Exception {
byte[] bytes = new byte[] { 1, 2, 3 };
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
byte[] convert = conversionService.convert(byteBuffer, byte[].class);
byte[] convert = this.conversionService.convert(byteBuffer, byte[].class);
assertThat(convert).isNotSameAs(bytes);
assertThat(convert).isEqualTo(bytes);
}
@Test
void byteBufferToOtherType() {
void byteBufferToOtherType() throws Exception {
byte[] bytes = new byte[] { 1, 2, 3 };
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
OtherType convert = conversionService.convert(byteBuffer, OtherType.class);
OtherType convert = this.conversionService.convert(byteBuffer, OtherType.class);
assertThat(convert.bytes).isNotSameAs(bytes);
assertThat(convert.bytes).isEqualTo(bytes);
}
@Test
void otherTypeToByteBuffer() {
void otherTypeToByteBuffer() throws Exception {
byte[] bytes = new byte[] { 1, 2, 3 };
OtherType otherType = new OtherType(bytes);
ByteBuffer convert = conversionService.convert(otherType, ByteBuffer.class);
ByteBuffer convert = this.conversionService.convert(otherType, ByteBuffer.class);
assertThat(convert.array()).isNotSameAs(bytes);
assertThat(convert.array()).isEqualTo(bytes);
}
@Test
void byteBufferToByteBuffer() {
void byteBufferToByteBuffer() throws Exception {
byte[] bytes = new byte[] { 1, 2, 3 };
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
ByteBuffer convert = conversionService.convert(byteBuffer, ByteBuffer.class);
ByteBuffer convert = this.conversionService.convert(byteBuffer, ByteBuffer.class);
assertThat(convert).isNotSameAs(byteBuffer.rewind());
assertThat(convert).isEqualTo(byteBuffer.rewind());
assertThat(convert).isEqualTo(ByteBuffer.wrap(bytes));
@@ -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.
@@ -49,11 +49,11 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
*/
class CollectionToCollectionConverterTests {
private final GenericConversionService conversionService = new GenericConversionService();
private GenericConversionService conversionService = new GenericConversionService();
@BeforeEach
void setup() {
void setUp() {
conversionService.addConverter(new CollectionToCollectionConverter(conversionService));
}
@@ -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.
@@ -38,7 +38,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author Keith Donald
* @author Phillip Webb
* @author Phil Webb
* @author Juergen Hoeller
*/
class MapToMapConverterTests {
@@ -47,7 +47,7 @@ class MapToMapConverterTests {
@BeforeEach
void setup() {
void setUp() {
conversionService.addConverter(new MapToMapConverter(conversionService));
}
@@ -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.
@@ -18,7 +18,6 @@ package org.springframework.core.convert.support;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.core.convert.ConverterNotFoundException;
@@ -30,19 +29,15 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* Unit tests for {@link ObjectToObjectConverter}.
*
* @author Sam Brannen
* @author Phillip Webb
* @author Phil Webb
* @since 5.3.21
* @see org.springframework.core.convert.converter.DefaultConversionServiceTests#convertObjectToObjectUsingValueOfMethod()
*/
class ObjectToObjectConverterTests {
private final GenericConversionService conversionService = new GenericConversionService();
@BeforeEach
void setup() {
conversionService.addConverter(new ObjectToObjectConverter());
}
private final GenericConversionService conversionService = new GenericConversionService() {{
addConverter(new ObjectToObjectConverter());
}};
/**
@@ -52,7 +47,7 @@ class ObjectToObjectConverterTests {
@Test
void nonStaticToTargetTypeSimpleNameMethodWithMatchingReturnType() {
assertThat(conversionService.canConvert(Source.class, Data.class))
.as("can convert Source to Data").isTrue();
.as("can convert Source to Data").isTrue();
Data data = conversionService.convert(new Source("test"), Data.class);
assertThat(data).asString().isEqualTo("test");
}
@@ -60,21 +55,21 @@ class ObjectToObjectConverterTests {
@Test
void nonStaticToTargetTypeSimpleNameMethodWithDifferentReturnType() {
assertThat(conversionService.canConvert(Text.class, Data.class))
.as("can convert Text to Data").isFalse();
.as("can convert Text to Data").isFalse();
assertThat(conversionService.canConvert(Text.class, Optional.class))
.as("can convert Text to Optional").isFalse();
.as("can convert Text to Optional").isFalse();
assertThatExceptionOfType(ConverterNotFoundException.class)
.as("convert Text to Data")
.isThrownBy(() -> conversionService.convert(new Text("test"), Data.class));
.as("convert Text to Data")
.isThrownBy(() -> conversionService.convert(new Text("test"), Data.class));
}
@Test
void staticValueOfFactoryMethodWithDifferentReturnType() {
assertThat(conversionService.canConvert(String.class, Data.class))
.as("can convert String to Data").isFalse();
.as("can convert String to Data").isFalse();
assertThatExceptionOfType(ConverterNotFoundException.class)
.as("convert String to Data")
.isThrownBy(() -> conversionService.convert("test", Data.class));
.as("convert String to Data")
.isThrownBy(() -> conversionService.convert("test", Data.class));
}
@@ -89,8 +84,8 @@ class ObjectToObjectConverterTests {
public Data toData() {
return new Data(this.value);
}
}
}
static class Text {
@@ -103,8 +98,8 @@ class ObjectToObjectConverterTests {
public Optional<Data> toData() {
return Optional.of(new Data(this.value));
}
}
}
static class Data {
@@ -120,8 +115,9 @@ class ObjectToObjectConverterTests {
}
public static Optional<Data> valueOf(String string) {
return (string != null ? Optional.of(new Data(string)) : Optional.empty());
return (string != null) ? Optional.of(new Data(string)) : Optional.empty();
}
}
}
@@ -1078,8 +1078,8 @@ class ObjectUtilsTests {
void nullSafeConciseToStringForEmptyCollections() {
List<String> list = Collections.emptyList();
Set<Integer> set = Collections.emptySet();
assertThat(ObjectUtils.nullSafeConciseToString(list)).isEqualTo("[...]");
assertThat(ObjectUtils.nullSafeConciseToString(set)).isEqualTo("[...]");
assertThat(ObjectUtils.nullSafeConciseToString(list)).isEqualTo("[]");
assertThat(ObjectUtils.nullSafeConciseToString(set)).isEqualTo("[]");
}
@Test
@@ -1094,7 +1094,7 @@ class ObjectUtilsTests {
@Test
void nullSafeConciseToStringForEmptyMaps() {
Map<String, Object> map = Collections.emptyMap();
assertThat(ObjectUtils.nullSafeConciseToString(map)).isEqualTo("{...}");
assertThat(ObjectUtils.nullSafeConciseToString(map)).isEqualTo("{}");
}
@Test
@@ -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.
@@ -28,7 +28,7 @@ import org.springframework.core.env.PropertySource;
*
* The {@link #setProperty} and {@link #withProperty} methods are exposed for
* convenience, for example:
* <pre class="code">
* <pre>
* {@code
* PropertySource<?> source = new MockPropertySource().withProperty("foo", "bar");
* }
@@ -77,7 +77,7 @@ public class MockPropertySource extends PropertiesPropertySource {
/**
* Create a new {@code MockPropertySource} with the given name and backed by the given
* {@link Properties} object.
* {@link Properties} object
* @param name the {@linkplain #getName() name} of the property source
* @param properties the properties to use
*/
@@ -99,7 +99,7 @@ public class MockPropertySource extends PropertiesPropertySource {
* @return this {@link MockPropertySource} instance
*/
public MockPropertySource withProperty(String name, Object value) {
setProperty(name, value);
this.setProperty(name, value);
return this;
}
@@ -77,6 +77,7 @@ import org.springframework.expression.spel.ast.Ternary;
import org.springframework.expression.spel.ast.TypeReference;
import org.springframework.expression.spel.ast.VariableReference;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@@ -136,13 +137,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
this.tokenStreamPointer = 0;
this.constructedNodes.clear();
SpelNodeImpl ast = eatExpression();
if (ast == null) {
throw new SpelParseException(this.expressionString, 0, SpelMessage.OOD);
}
Assert.state(ast != null, "No node");
Token t = peekToken();
if (t != null) {
throw new SpelParseException(this.expressionString, t.startPos, SpelMessage.MORE_INPUT, toString(nextToken()));
throw new SpelParseException(t.startPos, SpelMessage.MORE_INPUT, toString(nextToken()));
}
Assert.isTrue(this.constructedNodes.isEmpty(), "At least one node expected");
return new SpelExpression(expressionString, ast, this.configuration);
}
catch (InternalParseException ex) {
@@ -254,20 +254,20 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
if (tk == TokenKind.EQ) {
return new OpEQ(t.startPos, t.endPos, expr, rhExpr);
}
if (tk == TokenKind.NE) {
return new OpNE(t.startPos, t.endPos, expr, rhExpr);
}
Assert.isTrue(tk == TokenKind.NE, "Not-equals token expected");
return new OpNE(t.startPos, t.endPos, expr, rhExpr);
}
if (tk == TokenKind.INSTANCEOF) {
return new OperatorInstanceof(t.startPos, t.endPos, expr, rhExpr);
}
if (tk == TokenKind.MATCHES) {
return new OperatorMatches(this.patternCache, t.startPos, t.endPos, expr, rhExpr);
}
if (tk == TokenKind.BETWEEN) {
return new OperatorBetween(t.startPos, t.endPos, expr, rhExpr);
}
Assert.isTrue(tk == TokenKind.BETWEEN, "Between token expected");
return new OperatorBetween(t.startPos, t.endPos, expr, rhExpr);
}
return expr;
}
@@ -304,7 +304,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
else if (t.kind == TokenKind.DIV) {
expr = new OpDivide(t.startPos, t.endPos, expr, rhExpr);
}
else if (t.kind == TokenKind.MOD) {
else {
Assert.isTrue(t.kind == TokenKind.MOD, "Mod token expected");
expr = new OpModulus(t.startPos, t.endPos, expr, rhExpr);
}
}
@@ -334,21 +335,18 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
// unaryExpression: (PLUS^ | MINUS^ | BANG^ | INC^ | DEC^) unaryExpression | primaryExpression ;
@Nullable
private SpelNodeImpl eatUnaryExpression() {
if (peekToken(TokenKind.NOT, TokenKind.PLUS, TokenKind.MINUS)) {
if (peekToken(TokenKind.PLUS, TokenKind.MINUS, TokenKind.NOT)) {
Token t = takeToken();
SpelNodeImpl expr = eatUnaryExpression();
if (expr == null) {
throw internalException(t.startPos, SpelMessage.OOD);
}
Assert.state(expr != null, "No node");
if (t.kind == TokenKind.NOT) {
return new OperatorNot(t.startPos, t.endPos, expr);
}
if (t.kind == TokenKind.PLUS) {
return new OpPlus(t.startPos, t.endPos, expr);
}
if (t.kind == TokenKind.MINUS) {
return new OpMinus(t.startPos, t.endPos, expr);
}
Assert.isTrue(t.kind == TokenKind.MINUS, "Minus token expected");
return new OpMinus(t.startPos, t.endPos, expr);
}
if (peekToken(TokenKind.INC, TokenKind.DEC)) {
Token t = takeToken();
@@ -356,9 +354,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
if (t.getKind() == TokenKind.INC) {
return new OpInc(t.startPos, t.endPos, false, expr);
}
if (t.kind == TokenKind.DEC) {
return new OpDec(t.startPos, t.endPos, false, expr);
}
return new OpDec(t.startPos, t.endPos, false, expr);
}
return eatPrimaryExpression();
}
@@ -418,6 +414,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
return pop();
}
if (peekToken() == null) {
// unexpectedly ran out of data
throw internalException(t.startPos, SpelMessage.OOD);
}
else {
@@ -463,7 +460,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
private void eatConstructorArgs(List<SpelNodeImpl> accumulatedArguments) {
if (!peekToken(TokenKind.LPAREN)) {
throw internalException(positionOf(peekToken()), SpelMessage.MISSING_CONSTRUCTOR_ARGS);
throw new InternalParseException(new SpelParseException(this.expressionString,
positionOf(peekToken()), SpelMessage.MISSING_CONSTRUCTOR_ARGS));
}
consumeArguments(accumulatedArguments);
eatToken(TokenKind.RPAREN);
@@ -474,9 +472,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
*/
private void consumeArguments(List<SpelNodeImpl> accumulatedArguments) {
Token t = peekToken();
if (t == null) {
return;
}
Assert.state(t != null, "Expected token");
int pos = t.startPos;
Token next;
do {
@@ -579,7 +575,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
private boolean maybeEatTypeReference() {
if (peekToken(TokenKind.IDENTIFIER)) {
Token typeName = peekToken();
if (typeName == null || !"T".equals(typeName.stringValue())) {
Assert.state(typeName != null, "Expected token");
if (!"T".equals(typeName.stringValue())) {
return false;
}
// It looks like a type reference but is T being used as a map key?
@@ -608,7 +605,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
private boolean maybeEatNullReference() {
if (peekToken(TokenKind.IDENTIFIER)) {
Token nullToken = peekToken();
if (nullToken == null || !"null".equalsIgnoreCase(nullToken.stringValue())) {
Assert.state(nullToken != null, "Expected token");
if (!"null".equalsIgnoreCase(nullToken.stringValue())) {
return false;
}
nextToken();
@@ -621,13 +619,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
//projection: PROJECT^ expression RCURLY!;
private boolean maybeEatProjection(boolean nullSafeNavigation) {
Token t = peekToken();
if (t == null || !peekToken(TokenKind.PROJECT, true)) {
if (!peekToken(TokenKind.PROJECT, true)) {
return false;
}
Assert.state(t != null, "No token");
SpelNodeImpl expr = eatExpression();
if (expr == null) {
throw internalException(t.startPos, SpelMessage.OOD);
}
Assert.state(expr != null, "No node");
eatToken(TokenKind.RSQUARE);
this.constructedNodes.push(new Projection(nullSafeNavigation, t.startPos, t.endPos, expr));
return true;
@@ -637,13 +634,15 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
// map = LCURLY (key ':' value (COMMA key ':' value)*) RCURLY
private boolean maybeEatInlineListOrMap() {
Token t = peekToken();
if (t == null || !peekToken(TokenKind.LCURLY, true)) {
if (!peekToken(TokenKind.LCURLY, true)) {
return false;
}
Assert.state(t != null, "No token");
SpelNodeImpl expr = null;
Token closingCurly = peekToken();
if (closingCurly != null && peekToken(TokenKind.RCURLY, true)) {
if (peekToken(TokenKind.RCURLY, true)) {
// empty list '{}'
Assert.state(closingCurly != null, "No token");
expr = new InlineList(t.startPos, closingCurly.endPos);
}
else if (peekToken(TokenKind.COLON, true)) {
@@ -696,13 +695,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
private boolean maybeEatIndexer() {
Token t = peekToken();
if (t == null || !peekToken(TokenKind.LSQUARE, true)) {
if (!peekToken(TokenKind.LSQUARE, true)) {
return false;
}
Assert.state(t != null, "No token");
SpelNodeImpl expr = eatExpression();
if (expr == null) {
throw internalException(t.startPos, SpelMessage.MISSING_SELECTION_EXPRESSION);
}
Assert.state(expr != null, "No node");
eatToken(TokenKind.RSQUARE);
this.constructedNodes.push(new Indexer(t.startPos, t.endPos, expr));
return true;
@@ -710,9 +708,10 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
private boolean maybeEatSelection(boolean nullSafeNavigation) {
Token t = peekToken();
if (t == null || !peekSelectToken()) {
if (!peekSelectToken()) {
return false;
}
Assert.state(t != null, "No token");
nextToken();
SpelNodeImpl expr = eatExpression();
if (expr == null) {
@@ -890,14 +889,9 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
//parenExpr : LPAREN! expression RPAREN!;
private boolean maybeEatParenExpression() {
if (peekToken(TokenKind.LPAREN)) {
Token t = nextToken();
if (t == null) {
return false;
}
nextToken();
SpelNodeImpl expr = eatExpression();
if (expr == null) {
throw internalException(t.startPos, SpelMessage.OOD);
}
Assert.state(expr != null, "No node");
eatToken(TokenKind.RPAREN);
push(expr);
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.
@@ -65,7 +65,7 @@ class Token {
public boolean isNumericRelationalOperator() {
return (this.kind == TokenKind.GT || this.kind == TokenKind.GE || this.kind == TokenKind.LT ||
this.kind == TokenKind.LE || this.kind == TokenKind.EQ || this.kind == TokenKind.NE);
this.kind == TokenKind.LE || this.kind==TokenKind.EQ || this.kind==TokenKind.NE);
}
public String stringValue() {
@@ -87,14 +87,14 @@ class Token {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[').append(this.kind);
StringBuilder s = new StringBuilder();
s.append('[').append(this.kind.toString());
if (this.kind.hasPayload()) {
sb.append(':').append(this.data);
s.append(':').append(this.data);
}
sb.append(']');
sb.append('(').append(this.startPos).append(',').append(this.endPos).append(')');
return sb.toString();
s.append(']');
s.append('(').append(this.startPos).append(',').append(this.endPos).append(')');
return s.toString();
}
}
@@ -39,9 +39,7 @@ import static org.springframework.expression.spel.SpelMessage.NON_TERMINATING_DO
import static org.springframework.expression.spel.SpelMessage.NON_TERMINATING_QUOTED_STRING;
import static org.springframework.expression.spel.SpelMessage.NOT_AN_INTEGER;
import static org.springframework.expression.spel.SpelMessage.NOT_A_LONG;
import static org.springframework.expression.spel.SpelMessage.OOD;
import static org.springframework.expression.spel.SpelMessage.REAL_CANNOT_BE_LONG;
import static org.springframework.expression.spel.SpelMessage.RIGHT_OPERAND_PROBLEM;
import static org.springframework.expression.spel.SpelMessage.RUN_OUT_OF_ARGUMENTS;
import static org.springframework.expression.spel.SpelMessage.UNEXPECTED_DATA_AFTER_DOT;
import static org.springframework.expression.spel.SpelMessage.UNEXPECTED_ESCAPE_CHAR;
@@ -78,8 +76,8 @@ class SpelParserTests {
private static void assertNullOrEmptyExpressionIsRejected(ThrowingCallable throwingCallable) {
assertThatIllegalArgumentException()
.isThrownBy(throwingCallable)
.withMessage("'expressionString' must not be null or blank");
.isThrownBy(throwingCallable)
.withMessage("'expressionString' must not be null or blank");
}
@Test
@@ -154,13 +152,7 @@ class SpelParserTests {
assertParseException(() -> parser.parseRaw("new String(3"), RUN_OUT_OF_ARGUMENTS, 10);
assertParseException(() -> parser.parseRaw("new String("), RUN_OUT_OF_ARGUMENTS, 10);
assertParseException(() -> parser.parseRaw("\"abc"), NON_TERMINATING_DOUBLE_QUOTED_STRING, 0);
assertParseException(() -> parser.parseRaw("abc\""), NON_TERMINATING_DOUBLE_QUOTED_STRING, 3);
assertParseException(() -> parser.parseRaw("'abc"), NON_TERMINATING_QUOTED_STRING, 0);
assertParseException(() -> parser.parseRaw("abc'"), NON_TERMINATING_QUOTED_STRING, 3);
assertParseException(() -> parser.parseRaw("("), OOD, 0);
assertParseException(() -> parser.parseRaw(")"), OOD, 0);
assertParseException(() -> parser.parseRaw("+"), OOD, 0);
assertParseException(() -> parser.parseRaw("1+"), RIGHT_OPERAND_PROBLEM, 1);
}
@Test
@@ -385,7 +377,7 @@ class SpelParserTests {
private void checkNumberError(String expression, SpelMessage expectedMessage) {
assertParseExceptionThrownBy(() -> parser.parseRaw(expression))
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(expectedMessage));
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(expectedMessage));
}
private static ThrowableAssertAlternative<SpelParseException> assertParseExceptionThrownBy(ThrowingCallable throwingCallable) {
@@ -394,18 +386,15 @@ class SpelParserTests {
private static void assertParseException(ThrowingCallable throwingCallable, SpelMessage expectedMessage, int expectedPosition) {
assertParseExceptionThrownBy(throwingCallable)
.satisfies(parseExceptionRequirements(expectedMessage, expectedPosition));
.satisfies(parseExceptionRequirements(expectedMessage, expectedPosition));
}
private static <E extends SpelParseException> Consumer<E> parseExceptionRequirements(
SpelMessage expectedMessage, int expectedPosition) {
return ex -> {
assertThat(ex.getMessageCode()).isEqualTo(expectedMessage);
assertThat(ex.getPosition()).isEqualTo(expectedPosition);
if (ex.getExpressionString() != null) {
assertThat(ex.getMessage()).contains(ex.getExpressionString());
}
assertThat(ex.getMessage()).contains(ex.getExpressionString());
};
}
@@ -77,25 +77,7 @@ public abstract class LogFactory {
*/
@Deprecated
public static LogFactory getFactory() {
return new LogFactory() {
@Override
public Object getAttribute(String name) {
return null;
}
@Override
public String[] getAttributeNames() {
return new String[0];
}
@Override
public void removeAttribute(String name) {
}
@Override
public void setAttribute(String name, Object value) {
}
@Override
public void release() {
}
};
return new LogFactory() {};
}
/**
@@ -124,19 +106,29 @@ public abstract class LogFactory {
// Just in case some code happens to call uncommon Commons Logging methods...
@Deprecated
public abstract Object getAttribute(String name);
public Object getAttribute(String name) {
return null;
}
@Deprecated
public abstract String[] getAttributeNames();
public String[] getAttributeNames() {
return new String[0];
}
@Deprecated
public abstract void removeAttribute(String name);
public void removeAttribute(String name) {
// do nothing
}
@Deprecated
public abstract void setAttribute(String name, Object value);
public void setAttribute(String name, Object value) {
// do nothing
}
@Deprecated
public abstract void release();
public void release() {
// do nothing
}
@Deprecated
public static void release(ClassLoader classLoader) {
@@ -74,8 +74,4 @@ public class LogFactoryService extends LogFactory {
return this.attributes.keySet().toArray(new String[0]);
}
@Override
public void release() {
}
}
@@ -343,7 +343,7 @@ public class BeanPropertyRowMapper<T> implements RowMapper<T> {
bw.setPropertyValue(pd.getName(), value);
}
catch (TypeMismatchException ex) {
if (value == null && isPrimitivesDefaultedForNullValue()) {
if (value == null && this.primitivesDefaultedForNullValue) {
if (logger.isDebugEnabled()) {
String propertyType = ClassUtils.getQualifiedName(pd.getPropertyType());
logger.debug(String.format(
@@ -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.
@@ -35,13 +35,12 @@ import org.springframework.lang.Nullable;
* <p>Alternatively, the standard JDBC infrastructure can be mocked.
* However, mocking this interface constitutes significantly less work.
* As an alternative to a mock objects approach to testing data access code,
* consider the powerful integration testing support provided via the
* <em>Spring TestContext Framework</em>, in the {@code spring-test} artifact.
* consider the powerful integration testing support provided via the <em>Spring
* TestContext Framework</em>, in the {@code spring-test} artifact.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see JdbcTemplate
* @see org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations
*/
public interface JdbcOperations {
@@ -65,7 +65,8 @@ import org.springframework.util.StringUtils;
* It executes core JDBC workflow, leaving application code to provide SQL
* and extract results. This class executes SQL queries or updates, initiating
* iteration over ResultSets and catching JDBC exceptions and translating
* them to the common {@code org.springframework.dao} exception hierarchy.
* them to the generic, more informative exception hierarchy defined in the
* {@code org.springframework.dao} package.
*
* <p>Code using this class need only implement callback interfaces, giving
* them a clearly defined contract. The {@link PreparedStatementCreator} callback
@@ -74,8 +75,7 @@ import org.springframework.util.StringUtils;
* values from a ResultSet. See also {@link PreparedStatementSetter} and
* {@link RowMapper} for two popular alternative callback interfaces.
*
* <p>An instance of this template class is thread-safe once configured.
* Can be used within a service implementation via direct instantiation
* <p>Can be used within a service implementation via direct instantiation
* with a DataSource reference, or get prepared in an application context
* and given to services as bean reference. Note: The DataSource should
* always be configured as a bean in the application context, in the first case
@@ -88,11 +88,12 @@ import org.springframework.util.StringUtils;
* <p>All SQL operations performed by this class are logged at debug level,
* using "org.springframework.jdbc.core.JdbcTemplate" as log category.
*
* <p><b>NOTE: An instance of this class is thread-safe once configured.</b>
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Thomas Risberg
* @since May 3, 2001
* @see JdbcOperations
* @see PreparedStatementCreator
* @see PreparedStatementSetter
* @see CallableStatementCreator
@@ -102,7 +103,6 @@ import org.springframework.util.StringUtils;
* @see RowCallbackHandler
* @see RowMapper
* @see org.springframework.jdbc.support.SQLExceptionTranslator
* @see org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
*/
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
@@ -445,7 +445,9 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
logger.debug("Executing SQL query [" + sql + "]");
}
// Callback to execute the query.
/**
* Callback to execute the query.
*/
class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
@Override
@Nullable
@@ -540,7 +542,9 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
logger.debug("Executing SQL update [" + sql + "]");
}
// Callback to execute the update statement.
/**
* Callback to execute the update statement.
*/
class UpdateStatementCallback implements StatementCallback<Integer>, SqlProvider {
@Override
public Integer doInStatement(Statement stmt) throws SQLException {
@@ -566,7 +570,9 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
logger.debug("Executing SQL batch update of " + sql.length + " statements");
}
// Callback to execute the batch update.
/**
* Callback to execute the batch update.
*/
class BatchUpdateStatementCallback implements StatementCallback<int[]>, SqlProvider {
@Nullable
@@ -1370,7 +1376,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
}
}
}
if (!param.isResultsParameter()) {
if (!(param.isResultsParameter())) {
sqlColIndex++;
}
}
@@ -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.
@@ -32,10 +32,9 @@ import org.springframework.util.StringUtils;
/**
* {@link SqlParameterSource} implementation that obtains parameter values
* from bean properties of a given JavaBean object. The names of the bean
* properties have to match the parameter names. Supports components of
* record classes as well, with accessor methods matching parameter names.
* properties have to match the parameter names.
*
* <p>Uses a Spring {@link BeanWrapper} for bean property access underneath.
* <p>Uses a Spring BeanWrapper for bean property access underneath.
*
* @author Thomas Risberg
* @author Juergen Hoeller
@@ -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,19 +55,16 @@ import org.springframework.util.ConcurrentLruCache;
* done at execution time. It also allows for expanding a {@link java.util.List}
* of values to the appropriate number of placeholders.
*
* <p>An instance of this template class is thread-safe once configured.
* The underlying {@link org.springframework.jdbc.core.JdbcTemplate} is
* <p>The underlying {@link org.springframework.jdbc.core.JdbcTemplate} is
* exposed to allow for convenient access to the traditional
* {@link org.springframework.jdbc.core.JdbcTemplate} methods.
*
* <p><b>NOTE: An instance of this class is thread-safe once configured.</b>
*
* @author Thomas Risberg
* @author Juergen Hoeller
* @since 2.0
* @see NamedParameterJdbcOperations
* @see SqlParameterSource
* @see ResultSetExtractor
* @see RowCallbackHandler
* @see RowMapper
* @see org.springframework.jdbc.core.JdbcTemplate
*/
public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations {
@@ -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.
@@ -43,7 +43,7 @@ import org.springframework.util.StringUtils;
* Abstract class to provide base functionality for easy stored procedure calls
* based on configuration options and database meta-data.
*
* <p>This class provides the processing arrangement for {@link SimpleJdbcCall}.
* <p>This class provides the base SPI for {@link SimpleJdbcCall}.
*
* @author Thomas Risberg
* @author Juergen Hoeller
@@ -453,7 +453,7 @@ public abstract class AbstractJdbcCall {
/**
* Match the provided in parameter values with registered parameters and
* parameters defined via meta-data processing.
* @param args the parameter values provided as a Map
* @param args the parameter values provided in a Map
* @return a Map with parameter names and values
*/
protected Map<String, ?> matchInParameterValuesWithCallParameters(Map<String, ?> args) {
@@ -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.
@@ -50,10 +50,10 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Abstract class to provide base functionality for easy (batch) inserts
* Abstract class to provide base functionality for easy inserts
* based on configuration options and database meta-data.
*
* <p>This class provides the processing arrangement for {@link SimpleJdbcInsert}.
* <p>This class provides the base SPI for {@link SimpleJdbcInsert}.
*
* @author Thomas Risberg
* @author Juergen Hoeller
@@ -409,7 +409,7 @@ public abstract class AbstractJdbcInsert {
/**
* Delegate method to execute the insert, generating a single key.
*/
private Number executeInsertAndReturnKeyInternal(List<?> values) {
private Number executeInsertAndReturnKeyInternal(final List<?> values) {
KeyHolder kh = executeInsertAndReturnKeyHolderInternal(values);
if (kh.getKey() != null) {
return kh.getKey();
@@ -423,11 +423,11 @@ public abstract class AbstractJdbcInsert {
/**
* Delegate method to execute the insert, generating any number of keys.
*/
private KeyHolder executeInsertAndReturnKeyHolderInternal(List<?> values) {
private KeyHolder executeInsertAndReturnKeyHolderInternal(final List<?> values) {
if (logger.isDebugEnabled()) {
logger.debug("The following parameters are used for call " + getInsertString() + " with: " + values);
}
KeyHolder keyHolder = new GeneratedKeyHolder();
final KeyHolder keyHolder = new GeneratedKeyHolder();
if (this.tableMetaDataContext.isGetGeneratedKeysSupported()) {
getJdbcTemplate().update(
@@ -455,7 +455,7 @@ public abstract class AbstractJdbcInsert {
}
Assert.state(getTableName() != null, "No table name set");
String keyQuery = this.tableMetaDataContext.getSimpleQueryForGetGeneratedKey(
final String keyQuery = this.tableMetaDataContext.getSimpleQueryForGetGeneratedKey(
getTableName(), getGeneratedKeyNames()[0]);
Assert.state(keyQuery != null, "Query for simulating get generated keys must not be null");
@@ -535,8 +535,8 @@ public abstract class AbstractJdbcInsert {
/**
* Delegate method that executes a batch insert using the passed-in Maps of parameters.
* @param batch maps with parameter names and values to be used in the batch insert
* @return an array of number of rows affected
* @param batch array of Maps with parameter names and values to be used in batch insert
* @return array of number of rows affected
*/
@SuppressWarnings("unchecked")
protected int[] doExecuteBatch(Map<String, ?>... batch) {
@@ -549,10 +549,9 @@ public abstract class AbstractJdbcInsert {
}
/**
* Delegate method that executes a batch insert using the passed-in
* {@link SqlParameterSource SqlParameterSources}.
* @param batch parameter sources with names and values to be used in the batch insert
* @return an array of number of rows affected
* Delegate method that executes a batch insert using the passed-in {@link SqlParameterSource SqlParameterSources}.
* @param batch array of SqlParameterSource with parameter names and values to be used in insert
* @return array of number of rows affected
*/
protected int[] doExecuteBatch(SqlParameterSource... batch) {
checkCompiled();
@@ -607,7 +606,7 @@ public abstract class AbstractJdbcInsert {
* Match the provided in parameter values with registered parameters and parameters
* defined via meta-data processing.
* @param parameterSource the parameter values provided as a {@link SqlParameterSource}
* @return a List of values
* @return a Map with parameter names and values
*/
protected List<Object> matchInParameterValuesWithInsertColumns(SqlParameterSource parameterSource) {
return this.tableMetaDataContext.matchInParameterValuesWithInsertColumns(parameterSource);
@@ -616,8 +615,8 @@ public abstract class AbstractJdbcInsert {
/**
* Match the provided in parameter values with registered parameters and parameters
* defined via meta-data processing.
* @param args the parameter values provided as a Map
* @return a List of values
* @param args the parameter values provided in a Map
* @return a Map with parameter names and values
*/
protected List<Object> matchInParameterValuesWithInsertColumns(Map<String, ?> args) {
return this.tableMetaDataContext.matchInParameterValuesWithInsertColumns(args);
@@ -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.
@@ -47,7 +47,7 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
* any meta-data processing if you want to use parameter names that do not
* match what is declared during the stored procedure compilation.
*
* <p>The actual call is being handled using Spring's {@link JdbcTemplate}.
* <p>The actual insert is being handled using Spring's {@link JdbcTemplate}.
*
* <p>Many of the configuration methods return the current instance of the
* SimpleJdbcCall in order to provide the ability to chain multiple ones
@@ -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,17 +26,17 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.KeyHolder;
/**
* A SimpleJdbcInsert is a multithreaded, reusable object providing easy (batch) insert
* A SimpleJdbcInsert is a multithreaded, reusable object providing easy insert
* capabilities for a table. It provides meta-data processing to simplify the code
* needed to construct a basic insert statement. All you need to provide is the name
* of the table and a Map containing the column names and the column values.
* needed to construct a basic insert statement. All you need to provide is the
* name of the table and a Map containing the column names and the column values.
*
* <p>The meta-data processing is based on the DatabaseMetaData provided by the
* JDBC driver. As long as the JDBC driver can provide the names of the columns
* for a specified table then we can rely on this auto-detection feature. If that
* is not the case, then the column names must be specified explicitly.
*
* <p>The actual (batch) insert is handled using Spring's {@link JdbcTemplate}.
* <p>The actual insert is handled using Spring's {@link JdbcTemplate}.
*
* <p>Many of the configuration methods return the current instance of the
* SimpleJdbcInsert to provide the ability to chain multiple ones together
@@ -142,8 +142,8 @@ public class SimpleJdbcInsert extends AbstractJdbcInsert implements SimpleJdbcIn
return doExecuteAndReturnKeyHolder(parameterSource);
}
@SuppressWarnings("unchecked")
@Override
@SuppressWarnings("unchecked")
public int[] executeBatch(Map<String, ?>... batch) {
return doExecuteBatch(batch);
}
@@ -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.
@@ -31,8 +31,6 @@ import org.springframework.util.Assert;
*
* @author Juergen Hoeller
* @since 2.5.6
* @see #doTranslate
* @see #setFallbackTranslator
*/
public abstract class AbstractFallbackSQLExceptionTranslator implements SQLExceptionTranslator {
@@ -44,8 +42,8 @@ public abstract class AbstractFallbackSQLExceptionTranslator implements SQLExcep
/**
* Set the fallback translator to use when this translator cannot find a
* specific match itself.
* Override the default SQL state fallback translator
* (typically a {@link SQLStateSQLExceptionTranslator}).
*/
public void setFallbackTranslator(@Nullable SQLExceptionTranslator fallback) {
this.fallbackTranslator = fallback;
@@ -53,7 +51,6 @@ public abstract class AbstractFallbackSQLExceptionTranslator implements SQLExcep
/**
* Return the fallback exception translator, if any.
* @see #setFallbackTranslator
*/
@Nullable
public SQLExceptionTranslator getFallbackTranslator() {
@@ -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.
@@ -75,6 +75,8 @@ public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExcep
private static final int MESSAGE_SQL_THROWABLE_CONSTRUCTOR = 4;
private static final int MESSAGE_SQL_SQLEX_CONSTRUCTOR = 5;
/** Error codes used by this translator. */
@Nullable
private SingletonSupplier<SQLErrorCodes> sqlErrorCodes;
@@ -192,9 +194,9 @@ public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExcep
if (sqlErrorCodes != null) {
SQLExceptionTranslator customTranslator = sqlErrorCodes.getCustomSqlExceptionTranslator();
if (customTranslator != null) {
dae = customTranslator.translate(task, sql, sqlEx);
if (dae != null) {
return dae;
DataAccessException customDex = customTranslator.translate(task, sql, sqlEx);
if (customDex != null) {
return customDex;
}
}
}
@@ -222,10 +224,11 @@ public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExcep
for (CustomSQLErrorCodesTranslation customTranslation : customTranslations) {
if (Arrays.binarySearch(customTranslation.getErrorCodes(), errorCode) >= 0 &&
customTranslation.getExceptionClass() != null) {
dae = createCustomException(task, sql, sqlEx, customTranslation.getExceptionClass());
if (dae != null) {
DataAccessException customException = createCustomException(
task, sql, sqlEx, customTranslation.getExceptionClass());
if (customException != null) {
logTranslation(task, sql, sqlEx, true);
return dae;
return customException;
}
}
}
@@ -50,7 +50,7 @@ class BeanPropertyRowMapperTests extends AbstractRowMapperTests {
void overridingDifferentClassDefinedForMapping() {
BeanPropertyRowMapper mapper = new BeanPropertyRowMapper(Person.class);
assertThatExceptionOfType(InvalidDataAccessApiUsageException.class)
.isThrownBy(() -> mapper.setMappedClass(Long.class));
.isThrownBy(() -> mapper.setMappedClass(Long.class));
}
@Test
@@ -104,7 +104,7 @@ class BeanPropertyRowMapperTests extends AbstractRowMapperTests {
BeanPropertyRowMapper<ExtendedPerson> mapper = new BeanPropertyRowMapper<>(ExtendedPerson.class, true);
Mock mock = new Mock();
assertThatExceptionOfType(InvalidDataAccessApiUsageException.class)
.isThrownBy(() -> mock.getJdbcTemplate().query("select name, age, birth_date, balance from people", mapper));
.isThrownBy(() -> mock.getJdbcTemplate().query("select name, age, birth_date, balance from people", mapper));
}
@Test
@@ -112,7 +112,7 @@ class BeanPropertyRowMapperTests extends AbstractRowMapperTests {
BeanPropertyRowMapper<Person> mapper = new BeanPropertyRowMapper<>(Person.class);
Mock mock = new Mock(MockType.TWO);
assertThatExceptionOfType(TypeMismatchException.class)
.isThrownBy(() -> mock.getJdbcTemplate().query(SELECT_NULL_AS_AGE, mapper));
.isThrownBy(() -> mock.getJdbcTemplate().query(SELECT_NULL_AS_AGE, mapper));
}
@Test

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