mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e5d99ecf98 |
@@ -1,3 +1,3 @@
|
||||
# Enable auto-env through the sdkman_auto_env config
|
||||
# Add key=value pairs of SDKs to use below
|
||||
java=8.0.382-librca
|
||||
java=8.0.372-librca
|
||||
|
||||
+13
-13
@@ -28,18 +28,18 @@ configure(allprojects) { project ->
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.7"
|
||||
mavenBom "io.netty:netty-bom:4.1.107.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.41"
|
||||
mavenBom "io.netty:netty-bom:4.1.95.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.34"
|
||||
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR13"
|
||||
mavenBom "io.rsocket:rsocket-bom:1.1.3"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.54.v20240208"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.51.v20230217"
|
||||
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.5.32"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.5.2"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-serialization-bom:1.2.2"
|
||||
mavenBom "org.junit:junit-bom:5.8.2"
|
||||
}
|
||||
dependencies {
|
||||
dependencySet(group: 'org.apache.logging.log4j', version: '2.21.1') {
|
||||
dependencySet(group: 'org.apache.logging.log4j', version: '2.20.0') {
|
||||
entry 'log4j-api'
|
||||
entry 'log4j-core'
|
||||
entry 'log4j-jul'
|
||||
@@ -67,9 +67,9 @@ configure(allprojects) { project ->
|
||||
dependency "io.reactivex:rxjava:1.3.8"
|
||||
dependency "io.reactivex:rxjava-reactive-streams:1.2.1"
|
||||
dependency "io.reactivex.rxjava2:rxjava:2.2.21"
|
||||
dependency "io.reactivex.rxjava3:rxjava:3.1.8"
|
||||
dependency "io.smallrye.reactive:mutiny:1.9.0"
|
||||
dependency "io.projectreactor.tools:blockhound:1.0.8.RELEASE"
|
||||
dependency "io.reactivex.rxjava3:rxjava:3.1.5"
|
||||
dependency "io.smallrye.reactive:mutiny:1.8.0"
|
||||
dependency "io.projectreactor.tools:blockhound:1.0.6.RELEASE"
|
||||
|
||||
dependency "com.caucho:hessian:4.0.63"
|
||||
dependency "com.fasterxml:aalto-xml:1.3.1"
|
||||
@@ -96,7 +96,7 @@ configure(allprojects) { project ->
|
||||
|
||||
dependency "com.h2database:h2:2.1.214"
|
||||
dependency "com.github.ben-manes.caffeine:caffeine:2.9.3"
|
||||
dependency "com.github.librepdf:openpdf:1.3.33"
|
||||
dependency "com.github.librepdf:openpdf:1.3.30"
|
||||
dependency "com.rometools:rome:1.18.0"
|
||||
dependency "commons-io:commons-io:2.5"
|
||||
dependency "io.vavr:vavr:0.10.4"
|
||||
@@ -128,18 +128,18 @@ configure(allprojects) { project ->
|
||||
dependency "org.webjars:webjars-locator-core:0.48"
|
||||
dependency "org.webjars:underscorejs:1.8.3"
|
||||
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.82') {
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.78') {
|
||||
entry 'tomcat-util'
|
||||
entry('tomcat-websocket') {
|
||||
exclude group: "org.apache.tomcat", name: "tomcat-servlet-api"
|
||||
exclude group: "org.apache.tomcat", name: "tomcat-websocket-api"
|
||||
}
|
||||
}
|
||||
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.82') {
|
||||
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.78') {
|
||||
entry 'tomcat-embed-core'
|
||||
entry 'tomcat-embed-websocket'
|
||||
}
|
||||
dependencySet(group: 'io.undertow', version: '2.2.29.Final') {
|
||||
dependencySet(group: 'io.undertow', version: '2.2.25.Final') {
|
||||
entry 'undertow-core'
|
||||
entry('undertow-servlet') {
|
||||
exclude group: "org.jboss.spec.javax.servlet", name: "jboss-servlet-api_4.0_spec"
|
||||
@@ -340,7 +340,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
toolVersion = "10.12.7"
|
||||
toolVersion = "10.12.1"
|
||||
configDirectory.set(rootProject.file("src/checkstyle"))
|
||||
}
|
||||
|
||||
@@ -362,7 +362,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
// JSR-305 only used for non-required meta-annotations
|
||||
compileOnly("com.google.code.findbugs:jsr305")
|
||||
testCompileOnly("com.google.code.findbugs:jsr305")
|
||||
checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.41")
|
||||
checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.31")
|
||||
}
|
||||
|
||||
ext.javadocLinks = [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ubuntu:jammy-20240111
|
||||
FROM ubuntu:jammy-20230624
|
||||
|
||||
ADD setup.sh /setup.sh
|
||||
ADD get-jdk-url.sh /get-jdk-url.sh
|
||||
|
||||
@@ -3,10 +3,10 @@ set -e
|
||||
|
||||
case "$1" in
|
||||
java8)
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/8u402%2B7/bellsoft-jdk8u402+7-linux-amd64.tar.gz"
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/8u372+7/bellsoft-jdk8u372+7-linux-amd64.tar.gz"
|
||||
;;
|
||||
java17)
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/17.0.10%2B13/bellsoft-jdk17.0.10+13-linux-amd64.tar.gz"
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/17.0.7+7/bellsoft-jdk17.0.7+7-linux-amd64.tar.gz"
|
||||
;;
|
||||
*)
|
||||
echo $"Unknown java version"
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
version=5.3.32
|
||||
version=5.3.30
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
org.gradle.caching=true
|
||||
org.gradle.parallel=true
|
||||
|
||||
+3
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -35,8 +35,7 @@ import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Internal implementation of AspectJPointcutAdvisor.
|
||||
*
|
||||
* <p>Note that there will be one instance of this advisor for each target method.
|
||||
* Note that there will be one instance of this advisor for each target method.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -294,7 +293,7 @@ final class InstantiationModelAwarePointcutAdvisorImpl
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass, Object... args) {
|
||||
// This can match only on declared pointcut.
|
||||
return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass, args));
|
||||
return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass));
|
||||
}
|
||||
|
||||
private boolean isAspectMaterialized() {
|
||||
|
||||
+51
-70
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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,67 +38,56 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
* @author Adrian Colyer
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
class ArgumentBindingTests {
|
||||
public class ArgumentBindingTests {
|
||||
|
||||
@Test
|
||||
void annotationArgumentNameBinding() {
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TransactionalBean());
|
||||
proxyFactory.addAspect(PointcutWithAnnotationArgument.class);
|
||||
ITransactionalBean proxiedTestBean = proxyFactory.getProxy();
|
||||
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(proxiedTestBean::doInTransaction)
|
||||
.withMessage("Invoked with @Transactional");
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindingInPointcutUsedByAdvice() {
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
|
||||
public void testBindingInPointcutUsedByAdvice() {
|
||||
TestBean tb = new TestBean();
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
|
||||
proxyFactory.addAspect(NamedPointcutWithArgs.class);
|
||||
ITestBean proxiedTestBean = proxyFactory.getProxy();
|
||||
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> proxiedTestBean.setName("enigma"))
|
||||
.withMessage("enigma");
|
||||
ITestBean proxiedTestBean = proxyFactory.getProxy();
|
||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
||||
proxiedTestBean.setName("Supercalifragalisticexpialidocious"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindingWithDynamicAdvice() {
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
|
||||
proxyFactory.addAspect(DynamicPointcutWithArgs.class);
|
||||
ITestBean proxiedTestBean = proxyFactory.getProxy();
|
||||
public void testAnnotationArgumentNameBinding() {
|
||||
TransactionalBean tb = new TransactionalBean();
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
|
||||
proxyFactory.addAspect(PointcutWithAnnotationArgument.class);
|
||||
|
||||
proxiedTestBean.applyName(1);
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> proxiedTestBean.applyName("enigma"))
|
||||
.withMessage("enigma");
|
||||
ITransactionalBean proxiedTestBean = proxyFactory.getProxy();
|
||||
assertThatIllegalStateException().isThrownBy(
|
||||
proxiedTestBean::doInTransaction);
|
||||
}
|
||||
|
||||
@Test
|
||||
void parameterNameDiscoverWithReferencePointcut() throws Exception {
|
||||
public void testParameterNameDiscoverWithReferencePointcut() throws Exception {
|
||||
AspectJAdviceParameterNameDiscoverer discoverer =
|
||||
new AspectJAdviceParameterNameDiscoverer("somepc(formal) && set(* *)");
|
||||
discoverer.setRaiseExceptions(true);
|
||||
Method method = getClass().getDeclaredMethod("methodWithOneParam", String.class);
|
||||
assertThat(discoverer.getParameterNames(method)).containsExactly("formal");
|
||||
Method methodUsedForParameterTypeDiscovery =
|
||||
getClass().getMethod("methodWithOneParam", String.class);
|
||||
String[] pnames = discoverer.getParameterNames(methodUsedForParameterTypeDiscovery);
|
||||
assertThat(pnames.length).as("one parameter name").isEqualTo(1);
|
||||
assertThat(pnames[0]).isEqualTo("formal");
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void methodWithOneParam(String aParam) {
|
||||
public void methodWithOneParam(String aParam) {
|
||||
}
|
||||
|
||||
|
||||
interface ITransactionalBean {
|
||||
public interface ITransactionalBean {
|
||||
|
||||
@Transactional
|
||||
void doInTransaction();
|
||||
}
|
||||
|
||||
|
||||
static class TransactionalBean implements ITransactionalBean {
|
||||
public static class TransactionalBean implements ITransactionalBean {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@@ -106,46 +95,38 @@ class ArgumentBindingTests {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Mimics Spring's @Transactional annotation without actually introducing the dependency.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Transactional {
|
||||
}
|
||||
/**
|
||||
* Represents Spring's Transactional annotation without actually introducing the dependency
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Transactional {
|
||||
}
|
||||
|
||||
|
||||
@Aspect
|
||||
static class PointcutWithAnnotationArgument {
|
||||
@Aspect
|
||||
class PointcutWithAnnotationArgument {
|
||||
|
||||
@Around("execution(* org.springframework..*.*(..)) && @annotation(transactional)")
|
||||
public Object around(ProceedingJoinPoint pjp, Transactional transactional) throws Throwable {
|
||||
throw new IllegalStateException("Invoked with @Transactional");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Aspect
|
||||
static class NamedPointcutWithArgs {
|
||||
|
||||
@Pointcut("execution(* *(..)) && args(s,..)")
|
||||
public void pointcutWithArgs(String s) {}
|
||||
|
||||
@Around("pointcutWithArgs(aString)")
|
||||
public Object doAround(ProceedingJoinPoint pjp, String aString) throws Throwable {
|
||||
throw new IllegalArgumentException(aString);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Aspect("pertarget(execution(* *(..)))")
|
||||
static class DynamicPointcutWithArgs {
|
||||
|
||||
@Around("execution(* *(..)) && args(java.lang.String)")
|
||||
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
|
||||
throw new IllegalArgumentException(String.valueOf(pjp.getArgs()[0]));
|
||||
}
|
||||
@Around(value = "execution(* org.springframework..*.*(..)) && @annotation(transaction)")
|
||||
public Object around(ProceedingJoinPoint pjp, Transactional transaction) throws Throwable {
|
||||
System.out.println("Invoked with transaction " + transaction);
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Aspect
|
||||
class NamedPointcutWithArgs {
|
||||
|
||||
@Pointcut("execution(* *(..)) && args(s,..)")
|
||||
public void pointcutWithArgs(String s) {}
|
||||
|
||||
@Around("pointcutWithArgs(aString)")
|
||||
public Object doAround(ProceedingJoinPoint pjp, String aString) throws Throwable {
|
||||
System.out.println("got '" + aString + "' at '" + pjp + "'");
|
||||
throw new IllegalArgumentException(aString);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-4
@@ -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.
|
||||
@@ -1004,20 +1004,18 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
*/
|
||||
protected abstract static class PropertyHandler {
|
||||
|
||||
@Nullable
|
||||
private final Class<?> propertyType;
|
||||
|
||||
private final boolean readable;
|
||||
|
||||
private final boolean writable;
|
||||
|
||||
public PropertyHandler(@Nullable Class<?> propertyType, boolean readable, boolean writable) {
|
||||
public PropertyHandler(Class<?> propertyType, boolean readable, boolean writable) {
|
||||
this.propertyType = propertyType;
|
||||
this.readable = readable;
|
||||
this.writable = writable;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Class<?> getPropertyType() {
|
||||
return this.propertyType;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.time.temporal.Temporal;
|
||||
@@ -31,7 +30,6 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -789,28 +787,38 @@ public abstract class BeanUtils {
|
||||
if (editable != null) {
|
||||
if (!editable.isInstance(target)) {
|
||||
throw new IllegalArgumentException("Target class [" + target.getClass().getName() +
|
||||
"] not assignable to editable class [" + editable.getName() + "]");
|
||||
"] not assignable to Editable class [" + editable.getName() + "]");
|
||||
}
|
||||
actualEditable = editable;
|
||||
}
|
||||
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
|
||||
Set<String> ignoredProps = (ignoreProperties != null ? new HashSet<>(Arrays.asList(ignoreProperties)) : null);
|
||||
CachedIntrospectionResults sourceResults = (actualEditable != source.getClass() ?
|
||||
CachedIntrospectionResults.forClass(source.getClass()) : null);
|
||||
List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);
|
||||
|
||||
for (PropertyDescriptor targetPd : targetPds) {
|
||||
Method writeMethod = targetPd.getWriteMethod();
|
||||
if (writeMethod != null && (ignoredProps == null || !ignoredProps.contains(targetPd.getName()))) {
|
||||
PropertyDescriptor sourcePd = (sourceResults != null ?
|
||||
sourceResults.getPropertyDescriptor(targetPd.getName()) : targetPd);
|
||||
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
|
||||
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
|
||||
if (sourcePd != null) {
|
||||
Method readMethod = sourcePd.getReadMethod();
|
||||
if (readMethod != null) {
|
||||
if (isAssignable(writeMethod, readMethod)) {
|
||||
ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod);
|
||||
ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0);
|
||||
|
||||
// Ignore generic types in assignable check if either ResolvableType has unresolvable generics.
|
||||
boolean isAssignable =
|
||||
(sourceResolvableType.hasUnresolvableGenerics() || targetResolvableType.hasUnresolvableGenerics() ?
|
||||
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) :
|
||||
targetResolvableType.isAssignableFrom(sourceResolvableType));
|
||||
|
||||
if (isAssignable) {
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(readMethod);
|
||||
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
|
||||
readMethod.setAccessible(true);
|
||||
}
|
||||
Object value = readMethod.invoke(source);
|
||||
ReflectionUtils.makeAccessible(writeMethod);
|
||||
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
|
||||
writeMethod.setAccessible(true);
|
||||
}
|
||||
writeMethod.invoke(target, value);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
@@ -824,24 +832,6 @@ public abstract class BeanUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isAssignable(Method writeMethod, Method readMethod) {
|
||||
Type paramType = writeMethod.getGenericParameterTypes()[0];
|
||||
if (paramType instanceof Class) {
|
||||
return ClassUtils.isAssignable((Class<?>) paramType, readMethod.getReturnType());
|
||||
}
|
||||
else if (paramType.equals(readMethod.getGenericReturnType())) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
ResolvableType sourceType = ResolvableType.forMethodReturnType(readMethod);
|
||||
ResolvableType targetType = ResolvableType.forMethodParameter(writeMethod, 0);
|
||||
// Ignore generic types in assignable check if either ResolvableType has unresolvable generics.
|
||||
return (sourceType.hasUnresolvableGenerics() || targetType.hasUnresolvableGenerics() ?
|
||||
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) :
|
||||
targetType.isAssignableFrom(sourceType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to avoid a hard dependency on Kotlin at runtime.
|
||||
@@ -902,6 +892,7 @@ public abstract class BeanUtils {
|
||||
}
|
||||
return kotlinConstructor.callBy(argParameters);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -129,6 +129,7 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
|
||||
ReflectionUtils.makeAccessible(this.field);
|
||||
return this.field.get(getWrappedInstance());
|
||||
}
|
||||
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new InvalidPropertyException(getWrappedClass(),
|
||||
this.field.getName(), "Field is not accessible", ex);
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -292,7 +292,7 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
|
||||
if (actualValue != null) {
|
||||
actualValue = typeConverter.convertIfNecessary(actualValue, expectedValue.getClass());
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(expectedValue, actualValue)) {
|
||||
if (!expectedValue.equals(actualValue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -97,10 +97,10 @@ import org.springframework.util.StringUtils;
|
||||
* Supports autowiring constructors, properties by name, and properties by type.
|
||||
*
|
||||
* <p>The main template method to be implemented by subclasses is
|
||||
* {@link #resolveDependency(DependencyDescriptor, String, Set, TypeConverter)}, used for
|
||||
* autowiring. In case of a {@link org.springframework.beans.factory.ListableBeanFactory}
|
||||
* which is capable of searching its bean definitions, matching beans will typically be
|
||||
* implemented through such a search. Otherwise, simplified matching can be implemented.
|
||||
* {@link #resolveDependency(DependencyDescriptor, String, Set, TypeConverter)},
|
||||
* used for autowiring by type. In case of a factory which is capable of searching
|
||||
* its bean definitions, matching beans will typically be implemented through such
|
||||
* a search. For other factory styles, simplified matching algorithms can be implemented.
|
||||
*
|
||||
* <p>Note that this class does <i>not</i> assume or implement bean definition
|
||||
* registry capabilities. See {@link DefaultListableBeanFactory} for an implementation
|
||||
@@ -675,7 +675,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
// Apply SmartInstantiationAwareBeanPostProcessors to predict the
|
||||
// eventual type after a before-instantiation shortcut.
|
||||
if (targetType != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
|
||||
boolean matchingOnlyFactoryBean = (typesToMatch.length == 1 && typesToMatch[0] == FactoryBean.class);
|
||||
boolean matchingOnlyFactoryBean = typesToMatch.length == 1 && typesToMatch[0] == FactoryBean.class;
|
||||
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
|
||||
Class<?> predicted = bp.predictBeanType(targetType, beanName);
|
||||
if (predicted != null &&
|
||||
|
||||
+2
-2
@@ -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.
|
||||
@@ -749,7 +749,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
aliases.add(fullBeanName);
|
||||
}
|
||||
String[] retrievedAliases = super.getAliases(beanName);
|
||||
String prefix = (factoryPrefix ? FACTORY_BEAN_PREFIX : "");
|
||||
String prefix = factoryPrefix ? FACTORY_BEAN_PREFIX : "";
|
||||
for (String retrievedAlias : retrievedAliases) {
|
||||
String alias = prefix + retrievedAlias;
|
||||
if (!alias.equals(name)) {
|
||||
|
||||
+5
-1
@@ -107,7 +107,11 @@ class ConstructorResolver {
|
||||
|
||||
/**
|
||||
* "autowire constructor" (with constructor arguments by type) behavior.
|
||||
* Also applied if explicit constructor argument values are specified.
|
||||
* Also applied if explicit constructor argument values are specified,
|
||||
* matching all remaining arguments with beans from the bean factory.
|
||||
* <p>This corresponds to constructor injection: In this mode, a Spring
|
||||
* bean factory is able to host components that expect constructor-based
|
||||
* dependency resolution.
|
||||
* @param beanName the name of the bean
|
||||
* @param mbd the merged bean definition for the bean
|
||||
* @param chosenCtors chosen candidate constructors (or {@code null} if none)
|
||||
|
||||
+4
-7
@@ -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.
|
||||
@@ -78,10 +78,8 @@ public class PathEditor extends PropertyEditorSupport {
|
||||
if (nioPathCandidate && !text.startsWith("/")) {
|
||||
try {
|
||||
URI uri = new URI(text);
|
||||
String scheme = uri.getScheme();
|
||||
if (scheme != null) {
|
||||
// No NIO candidate except for "C:" style drive letters
|
||||
nioPathCandidate = (scheme.length() == 1);
|
||||
if (uri.getScheme() != null) {
|
||||
nioPathCandidate = false;
|
||||
// Let's try NIO file system providers via Paths.get(URI)
|
||||
setValue(Paths.get(uri).normalize());
|
||||
return;
|
||||
@@ -111,8 +109,7 @@ public class PathEditor extends PropertyEditorSupport {
|
||||
setValue(resource.getFile().toPath());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not retrieve file for " + resource + ": " + ex.getMessage());
|
||||
throw new IllegalArgumentException("Failed to retrieve file for " + resource, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -33,10 +33,6 @@ public interface ITestBean extends AgeHolder {
|
||||
|
||||
void setName(String name);
|
||||
|
||||
default void applyName(Object name) {
|
||||
setName(String.valueOf(name));
|
||||
}
|
||||
|
||||
ITestBean getSpouse();
|
||||
|
||||
void setSpouse(ITestBean spouse);
|
||||
|
||||
Vendored
+1
-1
@@ -236,7 +236,7 @@ public class CaffeineCacheManager implements CacheManager {
|
||||
* Build a common {@link CaffeineCache} instance for the specified cache name,
|
||||
* using the common Caffeine configuration specified on this cache manager.
|
||||
* <p>Delegates to {@link #adaptCaffeineCache} as the adaptation method to
|
||||
* Spring's cache abstraction (allowing for centralized decoration etc.),
|
||||
* Spring's cache abstraction (allowing for centralized decoration etc),
|
||||
* passing in a freshly built native Caffeine Cache instance.
|
||||
* @param name the name of the cache
|
||||
* @return the Spring CaffeineCache adapter (or a decorator thereof)
|
||||
|
||||
+3
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,7 +32,6 @@ import java.lang.annotation.Target;
|
||||
* @author Stephane Nicoll
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
* @see Cacheable
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -43,10 +42,8 @@ public @interface CacheConfig {
|
||||
* Names of the default caches to consider for caching operations defined
|
||||
* in the annotated class.
|
||||
* <p>If none is set at the operation level, these are used instead of the default.
|
||||
* <p>Names may be used to determine the target cache(s), to be resolved via the
|
||||
* configured {@link #cacheResolver()} which typically delegates to
|
||||
* {@link org.springframework.cache.CacheManager#getCache}.
|
||||
* For further details see {@link Cacheable#cacheNames()}.
|
||||
* <p>May be used to determine the target cache (or caches), matching the
|
||||
* qualifier value or the bean names of a specific bean definition.
|
||||
*/
|
||||
String[] cacheNames() default {};
|
||||
|
||||
|
||||
+2
-6
@@ -68,12 +68,8 @@ public @interface Cacheable {
|
||||
|
||||
/**
|
||||
* Names of the caches in which method invocation results are stored.
|
||||
* <p>Names may be used to determine the target cache(s), to be resolved via the
|
||||
* configured {@link #cacheResolver()} which typically delegates to
|
||||
* {@link org.springframework.cache.CacheManager#getCache}.
|
||||
* <p>This will usually be a single cache name. If multiple names are specified,
|
||||
* they will be consulted for a cache hit in the order of definition, and they
|
||||
* will all receive a put/evict request for the same newly cached value.
|
||||
* <p>Names may be used to determine the target cache (or caches), matching
|
||||
* the qualifier value or bean name of a specific bean definition.
|
||||
* @since 4.2
|
||||
* @see #value
|
||||
* @see CacheConfig#cacheNames
|
||||
|
||||
+3
-3
@@ -547,10 +547,10 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect a {@link CachePutRequest} for every {@link CacheOperation}
|
||||
* using the specified result value.
|
||||
* Collect the {@link CachePutRequest} for all {@link CacheOperation} using
|
||||
* the specified result value.
|
||||
* @param contexts the contexts to handle
|
||||
* @param result the result value
|
||||
* @param result the result value (never {@code null})
|
||||
* @param putRequests the collection to update
|
||||
*/
|
||||
private void collectPutRequests(Collection<CacheOperationContext> contexts,
|
||||
|
||||
Vendored
+2
-2
@@ -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.
|
||||
@@ -22,7 +22,7 @@ import org.springframework.lang.Nullable;
|
||||
* Abstract the invocation of a cache operation.
|
||||
*
|
||||
* <p>Does not provide a way to transmit checked exceptions but
|
||||
* provides a special exception that should be used to wrap any
|
||||
* provide a special exception that should be used to wrap any
|
||||
* exception that was thrown by the underlying invocation.
|
||||
* Callers are expected to handle this issue type specifically.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -121,7 +121,7 @@ public interface SmartLifecycle extends Lifecycle, Phased {
|
||||
/**
|
||||
* Return the phase that this lifecycle object is supposed to run in.
|
||||
* <p>The default implementation returns {@link #DEFAULT_PHASE} in order to
|
||||
* let {@code stop()} callbacks execute before regular {@code Lifecycle}
|
||||
* let {@code stop()} callbacks execute after regular {@code Lifecycle}
|
||||
* implementations.
|
||||
* @see #isAutoStartup()
|
||||
* @see #start()
|
||||
|
||||
+10
-11
@@ -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.
|
||||
@@ -62,13 +62,11 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* A component provider that scans for candidate components starting from a
|
||||
* specified base package. Can use the {@linkplain CandidateComponentsIndex component
|
||||
* index}, if it is available, and scans the classpath otherwise.
|
||||
*
|
||||
* <p>Candidate components are identified by applying exclude and include filters.
|
||||
* {@link AnnotationTypeFilter} and {@link AssignableTypeFilter} include filters
|
||||
* for an annotation/target-type that is annotated with {@link Indexed} are
|
||||
* A component provider that provides candidate components from a base package. Can
|
||||
* use {@link CandidateComponentsIndex the index} if it is available of scans the
|
||||
* classpath otherwise. Candidate components are identified by applying exclude and
|
||||
* include filters. {@link AnnotationTypeFilter}, {@link AssignableTypeFilter} include
|
||||
* filters on an annotation/superclass that are annotated with {@link Indexed} are
|
||||
* supported: if any other include filter is specified, the index is ignored and
|
||||
* classpath scanning is used instead.
|
||||
*
|
||||
@@ -306,7 +304,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
|
||||
|
||||
/**
|
||||
* Scan the component index or class path for candidate components.
|
||||
* Scan the class path for candidate components.
|
||||
* @param basePackage the package to check for annotated classes
|
||||
* @return a corresponding Set of autodetected bean definitions
|
||||
*/
|
||||
@@ -320,7 +318,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the component index can be used by this instance.
|
||||
* Determine if the index can be used by this instance.
|
||||
* @return {@code true} if the index is available and the configuration of this
|
||||
* instance is supported by it, {@code false} otherwise
|
||||
* @since 5.0
|
||||
@@ -456,7 +454,8 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, ex);
|
||||
throw new BeanDefinitionStoreException(
|
||||
"Failed to read candidate component class: " + resource, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -402,8 +402,8 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
|
||||
return;
|
||||
}
|
||||
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
|
||||
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
|
||||
}
|
||||
@@ -413,9 +413,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
|
||||
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
|
||||
}
|
||||
}
|
||||
else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
|
||||
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@EJB annotation is not supported on static methods");
|
||||
}
|
||||
@@ -425,9 +423,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
|
||||
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
|
||||
}
|
||||
}
|
||||
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
|
||||
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@Resource annotation is not supported on static methods");
|
||||
}
|
||||
|
||||
+3
-3
@@ -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.
|
||||
@@ -104,8 +104,8 @@ import org.springframework.stereotype.Component;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>{@code @Configuration} classes may not only be bootstrapped using component
|
||||
* scanning, but may also themselves <em>configure</em> component scanning using
|
||||
* <p>{@code @Configuration} classes may not only be bootstrapped using
|
||||
* component scanning, but may also themselves <em>configure</em> component scanning using
|
||||
* the {@link ComponentScan @ComponentScan} annotation:
|
||||
*
|
||||
* <pre class="code">
|
||||
|
||||
+16
-24
@@ -137,39 +137,31 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
implements ConfigurableApplicationContext {
|
||||
|
||||
/**
|
||||
* The name of the {@link LifecycleProcessor} bean in the context.
|
||||
* If none is supplied, a {@link DefaultLifecycleProcessor} is used.
|
||||
* @since 3.0
|
||||
* @see org.springframework.context.LifecycleProcessor
|
||||
* @see org.springframework.context.support.DefaultLifecycleProcessor
|
||||
* @see #start()
|
||||
* @see #stop()
|
||||
*/
|
||||
public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor";
|
||||
|
||||
/**
|
||||
* The name of the {@link MessageSource} bean in the context.
|
||||
* Name of the MessageSource bean in the factory.
|
||||
* If none is supplied, message resolution is delegated to the parent.
|
||||
* @see org.springframework.context.MessageSource
|
||||
* @see org.springframework.context.support.ResourceBundleMessageSource
|
||||
* @see org.springframework.context.support.ReloadableResourceBundleMessageSource
|
||||
* @see #getMessage(MessageSourceResolvable, Locale)
|
||||
* @see MessageSource
|
||||
*/
|
||||
public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";
|
||||
|
||||
/**
|
||||
* The name of the {@link ApplicationEventMulticaster} bean in the context.
|
||||
* If none is supplied, a {@link SimpleApplicationEventMulticaster} is used.
|
||||
* Name of the LifecycleProcessor bean in the factory.
|
||||
* If none is supplied, a DefaultLifecycleProcessor is used.
|
||||
* @see org.springframework.context.LifecycleProcessor
|
||||
* @see org.springframework.context.support.DefaultLifecycleProcessor
|
||||
*/
|
||||
public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor";
|
||||
|
||||
/**
|
||||
* Name of the ApplicationEventMulticaster bean in the factory.
|
||||
* If none is supplied, a default SimpleApplicationEventMulticaster is used.
|
||||
* @see org.springframework.context.event.ApplicationEventMulticaster
|
||||
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
|
||||
* @see #publishEvent(ApplicationEvent)
|
||||
* @see #addApplicationListener(ApplicationListener)
|
||||
*/
|
||||
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
|
||||
|
||||
/**
|
||||
* Boolean flag controlled by a {@code spring.spel.ignore} system property that
|
||||
* instructs Spring to ignore SpEL, i.e. to not initialize the SpEL infrastructure.
|
||||
* Boolean flag controlled by a {@code spring.spel.ignore} system property that instructs Spring to
|
||||
* ignore SpEL, i.e. to not initialize the SpEL infrastructure.
|
||||
* <p>The default is "false".
|
||||
*/
|
||||
private static final boolean shouldIgnoreSpel = SpringProperties.getFlag("spring.spel.ignore");
|
||||
@@ -211,7 +203,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
/** Flag that indicates whether this context has been closed already. */
|
||||
private final AtomicBoolean closed = new AtomicBoolean();
|
||||
|
||||
/** Synchronization monitor for "refresh" and "close". */
|
||||
/** Synchronization monitor for the "refresh" and "destroy". */
|
||||
private final Object startupShutdownMonitor = new Object();
|
||||
|
||||
/** Reference to the JVM shutdown hook, if registered. */
|
||||
@@ -219,7 +211,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
private Thread shutdownHook;
|
||||
|
||||
/** ResourcePatternResolver used by this context. */
|
||||
private final ResourcePatternResolver resourcePatternResolver;
|
||||
private ResourcePatternResolver resourcePatternResolver;
|
||||
|
||||
/** LifecycleProcessor for managing the lifecycle of beans within this context. */
|
||||
@Nullable
|
||||
|
||||
+1
-2
@@ -55,7 +55,7 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
|
||||
// override classes that have not been loaded yet. If not accessible, we will
|
||||
// always override requested classes, even when the classes have been loaded
|
||||
// by the parent ClassLoader already and cannot be transformed anymore anyway.
|
||||
Method method;
|
||||
Method method = null;
|
||||
try {
|
||||
method = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
@@ -63,7 +63,6 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
|
||||
catch (Throwable ex) {
|
||||
// Typically a JDK 9+ InaccessibleObjectException...
|
||||
// Avoid through JVM startup with --add-opens=java.base/java.lang=ALL-UNNAMED
|
||||
method = null;
|
||||
LogFactory.getLog(ContextTypeMatchClassLoader.class).debug(
|
||||
"ClassLoader.findLoadedClass not accessible -> will always override requested class", ex);
|
||||
}
|
||||
|
||||
+4
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -27,7 +27,6 @@ import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
@@ -144,7 +143,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
|
||||
/**
|
||||
* Set the PropertiesPersister to use for parsing properties files.
|
||||
* <p>The default is {@code ResourcePropertiesPersister}.
|
||||
* <p>The default is ResourcePropertiesPersister.
|
||||
* @see ResourcePropertiesPersister#INSTANCE
|
||||
*/
|
||||
public void setPropertiesPersister(@Nullable PropertiesPersister propertiesPersister) {
|
||||
@@ -402,7 +401,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
|
||||
/**
|
||||
* Refresh the PropertiesHolder for the given bundle filename.
|
||||
* <p>The holder can be {@code null} if not cached before, or a timed-out cache entry
|
||||
* The holder can be {@code null} if not cached before, or a timed-out cache entry
|
||||
* (potentially getting re-validated against the current last-modified timestamp).
|
||||
* @param filename the bundle filename (basename + Locale)
|
||||
* @param propHolder the current PropertiesHolder for the bundle
|
||||
@@ -563,7 +562,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
|
||||
private volatile long refreshTimestamp = -2;
|
||||
|
||||
private final Lock refreshLock = new ReentrantLock();
|
||||
private final ReentrantLock refreshLock = new ReentrantLock();
|
||||
|
||||
/** Cache to hold already generated MessageFormats per message code. */
|
||||
private final ConcurrentMap<String, Map<Locale, MessageFormat>> cachedMessageFormats =
|
||||
|
||||
@@ -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.
|
||||
@@ -29,7 +29,7 @@ import org.springframework.lang.Nullable;
|
||||
* {@link Runnable Runnables} based on different kinds of triggers.
|
||||
*
|
||||
* <p>This interface is separate from {@link SchedulingTaskExecutor} since it
|
||||
* usually represents a different kind of backend, i.e. a thread pool with
|
||||
* usually represents for a different kind of backend, i.e. a thread pool with
|
||||
* different characteristics and capabilities. Implementations may implement
|
||||
* both interfaces if they can handle both kinds of execution characteristics.
|
||||
*
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -100,9 +100,9 @@ public @interface Scheduled {
|
||||
|
||||
/**
|
||||
* A time zone for which the cron expression will be resolved. By default, this
|
||||
* attribute is the empty String (i.e. the scheduler's time zone will be used).
|
||||
* attribute is the empty String (i.e. the server's local time zone will be used).
|
||||
* @return a zone id accepted by {@link java.util.TimeZone#getTimeZone(String)},
|
||||
* or an empty String to indicate the scheduler's default time zone
|
||||
* or an empty String to indicate the server's default time zone
|
||||
* @since 4.0
|
||||
* @see org.springframework.scheduling.support.CronTrigger#CronTrigger(String, java.util.TimeZone)
|
||||
* @see java.util.TimeZone
|
||||
|
||||
+7
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,6 +27,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -83,7 +84,7 @@ import org.springframework.util.StringValueResolver;
|
||||
* "fixedRate", "fixedDelay", or "cron" expression provided via the annotation.
|
||||
*
|
||||
* <p>This post-processor is automatically registered by Spring's
|
||||
* {@code <task:annotation-driven>} XML element and also by the
|
||||
* {@code <task:annotation-driven>} XML element, and also by the
|
||||
* {@link EnableScheduling @EnableScheduling} annotation.
|
||||
*
|
||||
* <p>Autodetects any {@link SchedulingConfigurer} instances in the container,
|
||||
@@ -433,14 +434,14 @@ public class ScheduledAnnotationBeanPostProcessor
|
||||
Assert.isTrue(initialDelay == -1, "'initialDelay' not supported for cron triggers");
|
||||
processedSchedule = true;
|
||||
if (!Scheduled.CRON_DISABLED.equals(cron)) {
|
||||
CronTrigger trigger;
|
||||
TimeZone timeZone;
|
||||
if (StringUtils.hasText(zone)) {
|
||||
trigger = new CronTrigger(cron, StringUtils.parseTimeZoneString(zone));
|
||||
timeZone = StringUtils.parseTimeZoneString(zone);
|
||||
}
|
||||
else {
|
||||
trigger = new CronTrigger(cron);
|
||||
timeZone = TimeZone.getDefault();
|
||||
}
|
||||
tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, trigger)));
|
||||
tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+28
-24
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -29,15 +29,17 @@ import org.springframework.util.StringUtils;
|
||||
* Created using the {@code parse*} methods.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Juergen Hoeller
|
||||
* @since 5.3
|
||||
*/
|
||||
final class BitsCronField extends CronField {
|
||||
|
||||
public static final BitsCronField ZERO_NANOS = forZeroNanos();
|
||||
|
||||
private static final long MASK = 0xFFFFFFFFFFFFFFFFL;
|
||||
|
||||
|
||||
@Nullable
|
||||
private static BitsCronField zeroNanos = null;
|
||||
|
||||
|
||||
// we store at most 60 bits, for seconds and minutes, so a 64-bit long suffices
|
||||
private long bits;
|
||||
|
||||
@@ -46,14 +48,16 @@ final class BitsCronField extends CronField {
|
||||
super(type);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a {@code BitsCronField} enabled for 0 nanoseconds.
|
||||
*/
|
||||
private static BitsCronField forZeroNanos() {
|
||||
BitsCronField field = new BitsCronField(Type.NANO);
|
||||
field.setBit(0);
|
||||
return field;
|
||||
public static BitsCronField zeroNanos() {
|
||||
if (zeroNanos == null) {
|
||||
BitsCronField field = new BitsCronField(Type.NANO);
|
||||
field.setBit(0);
|
||||
zeroNanos = field;
|
||||
}
|
||||
return zeroNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,6 +108,7 @@ final class BitsCronField extends CronField {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static BitsCronField parseDate(String value, BitsCronField.Type type) {
|
||||
if (value.equals("?")) {
|
||||
value = "*";
|
||||
@@ -169,7 +174,6 @@ final class BitsCronField extends CronField {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T extends Temporal & Comparable<? super T>> T nextOrSame(T temporal) {
|
||||
@@ -213,6 +217,7 @@ final class BitsCronField extends CronField {
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void setBits(ValueRange range) {
|
||||
@@ -242,20 +247,7 @@ final class BitsCronField extends CronField {
|
||||
}
|
||||
|
||||
private void clearBit(int index) {
|
||||
this.bits &= ~(1L << index);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof BitsCronField)) {
|
||||
return false;
|
||||
}
|
||||
BitsCronField otherField = (BitsCronField) other;
|
||||
return (type() == otherField.type() && this.bits == otherField.bits);
|
||||
this.bits &= ~(1L << index);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -263,6 +255,18 @@ final class BitsCronField extends CronField {
|
||||
return Long.hashCode(this.bits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof BitsCronField)) {
|
||||
return false;
|
||||
}
|
||||
BitsCronField other = (BitsCronField) o;
|
||||
return type() == other.type() && this.bits == other.bits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(type().toString());
|
||||
|
||||
+36
-23
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -29,14 +29,9 @@ import org.springframework.util.StringUtils;
|
||||
* <a href="https://www.manpagez.com/man/5/crontab/">crontab expression</a>
|
||||
* that can calculate the next time it matches.
|
||||
*
|
||||
* <p>{@code CronExpression} instances are created through {@link #parse(String)};
|
||||
* the next match is determined with {@link #next(Temporal)}.
|
||||
*
|
||||
* <p>Supports a Quartz day-of-month/week field with an L/# expression. Follows
|
||||
* common cron conventions in every other respect, including 0-6 for SUN-SAT
|
||||
* (plus 7 for SUN as well). Note that Quartz deviates from the day-of-week
|
||||
* convention in cron through 1-7 for SUN-SAT whereas Spring strictly follows
|
||||
* cron even in combination with the optional Quartz-specific L/# expressions.
|
||||
* <p>{@code CronExpression} instances are created through
|
||||
* {@link #parse(String)}; the next match is determined with
|
||||
* {@link #next(Temporal)}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 5.3
|
||||
@@ -62,12 +57,18 @@ public final class CronExpression {
|
||||
private final String expression;
|
||||
|
||||
|
||||
private CronExpression(CronField seconds, CronField minutes, CronField hours,
|
||||
CronField daysOfMonth, CronField months, CronField daysOfWeek, String expression) {
|
||||
private CronExpression(
|
||||
CronField seconds,
|
||||
CronField minutes,
|
||||
CronField hours,
|
||||
CronField daysOfMonth,
|
||||
CronField months,
|
||||
CronField daysOfWeek,
|
||||
String expression) {
|
||||
|
||||
// Reverse order, to make big changes first.
|
||||
// To make sure we end up at 0 nanos, we add an extra field.
|
||||
this.fields = new CronField[] {daysOfWeek, months, daysOfMonth, hours, minutes, seconds, CronField.zeroNanos()};
|
||||
// reverse order, to make big changes first
|
||||
// to make sure we end up at 0 nanos, we add an extra field
|
||||
this.fields = new CronField[]{daysOfWeek, months, daysOfMonth, hours, minutes, seconds, CronField.zeroNanos()};
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@@ -120,8 +121,11 @@ public final class CronExpression {
|
||||
* {@code LW}), it means "the last weekday of the month".
|
||||
* </li>
|
||||
* <li>
|
||||
* In the "day of week" field, {@code dL} or {@code DDDL} stands for
|
||||
* "the last day of week {@code d} (or {@code DDD}) in the month".
|
||||
* In the "day of week" field, {@code L} stands for "the last day of the
|
||||
* week".
|
||||
* If prefixed by a number or three-letter name (i.e. {@code dL} or
|
||||
* {@code DDDL}), it means "the last day of week {@code d} (or {@code DDD})
|
||||
* in the month".
|
||||
* </li>
|
||||
* </ul>
|
||||
* </li>
|
||||
@@ -173,7 +177,7 @@ public final class CronExpression {
|
||||
* the cron format
|
||||
*/
|
||||
public static CronExpression parse(String expression) {
|
||||
Assert.hasLength(expression, "Expression must not be empty");
|
||||
Assert.hasLength(expression, "Expression string must not be empty");
|
||||
|
||||
expression = resolveMacros(expression);
|
||||
|
||||
@@ -266,19 +270,28 @@ public final class CronExpression {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
return (this == other || (other instanceof CronExpression &&
|
||||
Arrays.equals(this.fields, ((CronExpression) other).fields)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(this.fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o instanceof CronExpression) {
|
||||
CronExpression other = (CronExpression) o;
|
||||
return Arrays.equals(this.fields, other.fields);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the expression string used to create this {@code CronExpression}.
|
||||
* @return the expression string
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -29,24 +29,17 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Single field in a cron pattern. Created using the {@code parse*} methods,
|
||||
* the main and only entry point is {@link #nextOrSame(Temporal)}.
|
||||
*
|
||||
* <p>Supports a Quartz day-of-month/week field with an L/# expression. Follows
|
||||
* common cron conventions in every other respect, including 0-6 for SUN-SAT
|
||||
* (plus 7 for SUN as well). Note that Quartz deviates from the day-of-week
|
||||
* convention in cron through 1-7 for SUN-SAT whereas Spring strictly follows
|
||||
* cron even in combination with the optional Quartz-specific L/# expressions.
|
||||
* main and only entry point is {@link #nextOrSame(Temporal)}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 5.3
|
||||
*/
|
||||
abstract class CronField {
|
||||
|
||||
private static final String[] MONTHS = new String[]
|
||||
{"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
|
||||
private static final String[] MONTHS = new String[]{"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP",
|
||||
"OCT", "NOV", "DEC"};
|
||||
|
||||
private static final String[] DAYS = new String[]
|
||||
{"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
|
||||
private static final String[] DAYS = new String[]{"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
|
||||
|
||||
private final Type type;
|
||||
|
||||
@@ -55,12 +48,11 @@ abstract class CronField {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a {@code CronField} enabled for 0 nanoseconds.
|
||||
*/
|
||||
public static CronField zeroNanos() {
|
||||
return BitsCronField.ZERO_NANOS;
|
||||
return BitsCronField.zeroNanos();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,7 +169,6 @@ abstract class CronField {
|
||||
* day-of-month, month, day-of-week.
|
||||
*/
|
||||
protected enum Type {
|
||||
|
||||
NANO(ChronoField.NANO_OF_SECOND, ChronoUnit.SECONDS),
|
||||
SECOND(ChronoField.SECOND_OF_MINUTE, ChronoUnit.MINUTES, ChronoField.NANO_OF_SECOND),
|
||||
MINUTE(ChronoField.MINUTE_OF_HOUR, ChronoUnit.HOURS, ChronoField.SECOND_OF_MINUTE, ChronoField.NANO_OF_SECOND),
|
||||
@@ -186,18 +177,21 @@ abstract class CronField {
|
||||
MONTH(ChronoField.MONTH_OF_YEAR, ChronoUnit.YEARS, ChronoField.DAY_OF_MONTH, ChronoField.HOUR_OF_DAY, ChronoField.MINUTE_OF_HOUR, ChronoField.SECOND_OF_MINUTE, ChronoField.NANO_OF_SECOND),
|
||||
DAY_OF_WEEK(ChronoField.DAY_OF_WEEK, ChronoUnit.WEEKS, ChronoField.HOUR_OF_DAY, ChronoField.MINUTE_OF_HOUR, ChronoField.SECOND_OF_MINUTE, ChronoField.NANO_OF_SECOND);
|
||||
|
||||
|
||||
private final ChronoField field;
|
||||
|
||||
private final ChronoUnit higherOrder;
|
||||
|
||||
private final ChronoField[] lowerOrders;
|
||||
|
||||
|
||||
Type(ChronoField field, ChronoUnit higherOrder, ChronoField... lowerOrders) {
|
||||
this.field = field;
|
||||
this.higherOrder = higherOrder;
|
||||
this.lowerOrders = lowerOrders;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the value of this type for the given temporal.
|
||||
* @return the value of this type
|
||||
|
||||
+16
-25
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -27,14 +27,8 @@ import org.springframework.scheduling.TriggerContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Trigger} implementation for cron expressions. Wraps a
|
||||
* {@link CronExpression} which parses according to common crontab conventions.
|
||||
*
|
||||
* <p>Supports a Quartz day-of-month/week field with an L/# expression. Follows
|
||||
* common cron conventions in every other respect, including 0-6 for SUN-SAT
|
||||
* (plus 7 for SUN as well). Note that Quartz deviates from the day-of-week
|
||||
* convention in cron through 1-7 for SUN-SAT whereas Spring strictly follows
|
||||
* cron even in combination with the optional Quartz-specific L/# expressions.
|
||||
* {@link Trigger} implementation for cron expressions.
|
||||
* Wraps a {@link CronExpression}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Arjen Poutsma
|
||||
@@ -45,7 +39,6 @@ public class CronTrigger implements Trigger {
|
||||
|
||||
private final CronExpression expression;
|
||||
|
||||
@Nullable
|
||||
private final ZoneId zoneId;
|
||||
|
||||
|
||||
@@ -55,8 +48,7 @@ public class CronTrigger implements Trigger {
|
||||
* expression conventions
|
||||
*/
|
||||
public CronTrigger(String expression) {
|
||||
this.expression = CronExpression.parse(expression);
|
||||
this.zoneId = null;
|
||||
this(expression, ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,9 +58,7 @@ public class CronTrigger implements Trigger {
|
||||
* @param timeZone a time zone in which the trigger times will be generated
|
||||
*/
|
||||
public CronTrigger(String expression, TimeZone timeZone) {
|
||||
this.expression = CronExpression.parse(expression);
|
||||
Assert.notNull(timeZone, "TimeZone must not be null");
|
||||
this.zoneId = timeZone.toZoneId();
|
||||
this(expression, timeZone.toZoneId());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,8 +70,10 @@ public class CronTrigger implements Trigger {
|
||||
* @see CronExpression#parse(String)
|
||||
*/
|
||||
public CronTrigger(String expression, ZoneId zoneId) {
|
||||
this.expression = CronExpression.parse(expression);
|
||||
Assert.hasLength(expression, "Expression must not be empty");
|
||||
Assert.notNull(zoneId, "ZoneId must not be null");
|
||||
|
||||
this.expression = CronExpression.parse(expression);
|
||||
this.zoneId = zoneId;
|
||||
}
|
||||
|
||||
@@ -102,23 +94,22 @@ public class CronTrigger implements Trigger {
|
||||
*/
|
||||
@Override
|
||||
public Date nextExecutionTime(TriggerContext triggerContext) {
|
||||
Date timestamp = triggerContext.lastCompletionTime();
|
||||
if (timestamp != null) {
|
||||
Date date = triggerContext.lastCompletionTime();
|
||||
if (date != null) {
|
||||
Date scheduled = triggerContext.lastScheduledExecutionTime();
|
||||
if (scheduled != null && timestamp.before(scheduled)) {
|
||||
if (scheduled != null && date.before(scheduled)) {
|
||||
// Previous task apparently executed too early...
|
||||
// Let's simply use the last calculated execution time then,
|
||||
// in order to prevent accidental re-fires in the same second.
|
||||
timestamp = scheduled;
|
||||
date = scheduled;
|
||||
}
|
||||
}
|
||||
else {
|
||||
timestamp = new Date(triggerContext.getClock().millis());
|
||||
date = new Date(triggerContext.getClock().millis());
|
||||
}
|
||||
ZoneId zone = (this.zoneId != null ? this.zoneId : triggerContext.getClock().getZone());
|
||||
ZonedDateTime zonedTimestamp = ZonedDateTime.ofInstant(timestamp.toInstant(), zone);
|
||||
ZonedDateTime nextTimestamp = this.expression.next(zonedTimestamp);
|
||||
return (nextTimestamp != null ? Date.from(nextTimestamp.toInstant()) : null);
|
||||
ZonedDateTime dateTime = ZonedDateTime.ofInstant(date.toInstant(), this.zoneId);
|
||||
ZonedDateTime next = this.expression.next(dateTime);
|
||||
return (next != null ? Date.from(next.toInstant()) : null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+41
-46
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -29,16 +29,10 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Extension of {@link CronField} for
|
||||
* <a href="https://www.quartz-scheduler.org">Quartz</a>-specific fields.
|
||||
* <a href="https://www.quartz-scheduler.org>Quartz</a> -specific fields.
|
||||
* Created using the {@code parse*} methods, uses a {@link TemporalAdjuster}
|
||||
* internally.
|
||||
*
|
||||
* <p>Supports a Quartz day-of-month/week field with an L/# expression. Follows
|
||||
* common cron conventions in every other respect, including 0-6 for SUN-SAT
|
||||
* (plus 7 for SUN as well). Note that Quartz deviates from the day-of-week
|
||||
* convention in cron through 1-7 for SUN-SAT whereas Spring strictly follows
|
||||
* cron even in combination with the optional Quartz-specific L/# expressions.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 5.3
|
||||
*/
|
||||
@@ -66,18 +60,16 @@ final class QuartzCronField extends CronField {
|
||||
this.rollForwardType = rollForwardType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the given value is a Quartz day-of-month field.
|
||||
* Returns whether the given value is a Quartz day-of-month field.
|
||||
*/
|
||||
public static boolean isQuartzDaysOfMonthField(String value) {
|
||||
return value.contains("L") || value.contains("W");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given value into a days of months {@code QuartzCronField},
|
||||
* the fourth entry of a cron expression.
|
||||
* <p>Expects a "L" or "W" in the given value.
|
||||
* Parse the given value into a days of months {@code QuartzCronField}, the fourth entry of a cron expression.
|
||||
* Expects a "L" or "W" in the given value.
|
||||
*/
|
||||
public static QuartzCronField parseDaysOfMonth(String value) {
|
||||
int idx = value.lastIndexOf('L');
|
||||
@@ -86,14 +78,14 @@ final class QuartzCronField extends CronField {
|
||||
if (idx != 0) {
|
||||
throw new IllegalArgumentException("Unrecognized characters before 'L' in '" + value + "'");
|
||||
}
|
||||
else if (value.length() == 2 && value.charAt(1) == 'W') { // "LW"
|
||||
else if (value.length() == 2 && value.charAt(1) == 'W') { // "LW"
|
||||
adjuster = lastWeekdayOfMonth();
|
||||
}
|
||||
else {
|
||||
if (value.length() == 1) { // "L"
|
||||
if (value.length() == 1) { // "L"
|
||||
adjuster = lastDayOfMonth();
|
||||
}
|
||||
else { // "L-[0-9]+"
|
||||
else { // "L-[0-9]+"
|
||||
int offset = Integer.parseInt(value.substring(idx + 1));
|
||||
if (offset >= 0) {
|
||||
throw new IllegalArgumentException("Offset '" + offset + " should be < 0 '" + value + "'");
|
||||
@@ -111,7 +103,7 @@ final class QuartzCronField extends CronField {
|
||||
else if (idx != value.length() - 1) {
|
||||
throw new IllegalArgumentException("Unrecognized characters after 'W' in '" + value + "'");
|
||||
}
|
||||
else { // "[0-9]+W"
|
||||
else { // "[0-9]+W"
|
||||
int dayOfMonth = Integer.parseInt(value.substring(0, idx));
|
||||
dayOfMonth = Type.DAY_OF_MONTH.checkValidValue(dayOfMonth);
|
||||
TemporalAdjuster adjuster = weekdayNearestTo(dayOfMonth);
|
||||
@@ -122,16 +114,15 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given value is a Quartz day-of-week field.
|
||||
* Returns whether the given value is a Quartz day-of-week field.
|
||||
*/
|
||||
public static boolean isQuartzDaysOfWeekField(String value) {
|
||||
return value.contains("L") || value.contains("#");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given value into a days of week {@code QuartzCronField},
|
||||
* the sixth entry of a cron expression.
|
||||
* <p>Expects a "L" or "#" in the given value.
|
||||
* Parse the given value into a days of week {@code QuartzCronField}, the sixth entry of a cron expression.
|
||||
* Expects a "L" or "#" in the given value.
|
||||
*/
|
||||
public static QuartzCronField parseDaysOfWeek(String value) {
|
||||
int idx = value.lastIndexOf('L');
|
||||
@@ -144,7 +135,7 @@ final class QuartzCronField extends CronField {
|
||||
if (idx == 0) {
|
||||
throw new IllegalArgumentException("No day-of-week before 'L' in '" + value + "'");
|
||||
}
|
||||
else { // "[0-7]L"
|
||||
else { // "[0-7]L"
|
||||
DayOfWeek dayOfWeek = parseDayOfWeek(value.substring(0, idx));
|
||||
adjuster = lastInMonth(dayOfWeek);
|
||||
}
|
||||
@@ -166,6 +157,7 @@ final class QuartzCronField extends CronField {
|
||||
throw new IllegalArgumentException("Ordinal '" + ordinal + "' in '" + value +
|
||||
"' must be positive number ");
|
||||
}
|
||||
|
||||
TemporalAdjuster adjuster = dayOfWeekInMonth(ordinal, dayOfWeek);
|
||||
return new QuartzCronField(Type.DAY_OF_WEEK, Type.DAY_OF_MONTH, adjuster, value);
|
||||
}
|
||||
@@ -175,13 +167,14 @@ final class QuartzCronField extends CronField {
|
||||
private static DayOfWeek parseDayOfWeek(String value) {
|
||||
int dayOfWeek = Integer.parseInt(value);
|
||||
if (dayOfWeek == 0) {
|
||||
dayOfWeek = 7; // cron is 0 based; java.time 1 based
|
||||
dayOfWeek = 7; // cron is 0 based; java.time 1 based
|
||||
}
|
||||
try {
|
||||
return DayOfWeek.of(dayOfWeek);
|
||||
}
|
||||
catch (DateTimeException ex) {
|
||||
throw new IllegalArgumentException(ex.getMessage() + " '" + value + "'", ex);
|
||||
String msg = ex.getMessage() + " '" + value + "'";
|
||||
throw new IllegalArgumentException(msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,10 +213,10 @@ final class QuartzCronField extends CronField {
|
||||
Temporal lastDom = adjuster.adjustInto(temporal);
|
||||
Temporal result;
|
||||
int dow = lastDom.get(ChronoField.DAY_OF_WEEK);
|
||||
if (dow == 6) { // Saturday
|
||||
if (dow == 6) { // Saturday
|
||||
result = lastDom.minus(1, ChronoUnit.DAYS);
|
||||
}
|
||||
else if (dow == 7) { // Sunday
|
||||
else if (dow == 7) { // Sunday
|
||||
result = lastDom.minus(2, ChronoUnit.DAYS);
|
||||
}
|
||||
else {
|
||||
@@ -234,7 +227,7 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a temporal adjuster that finds the nth-to-last day of the month.
|
||||
* Return a temporal adjuster that finds the nth-to-last day of the month.
|
||||
* @param offset the negative offset, i.e. -3 means third-to-last
|
||||
* @return a nth-to-last day-of-month adjuster
|
||||
*/
|
||||
@@ -248,7 +241,7 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a temporal adjuster that finds the weekday nearest to the given
|
||||
* Return a temporal adjuster that finds the weekday nearest to the given
|
||||
* day-of-month. If {@code dayOfMonth} falls on a Saturday, the date is
|
||||
* moved back to Friday; if it falls on a Sunday (or if {@code dayOfMonth}
|
||||
* is 1 and it falls on a Saturday), it is moved forward to Monday.
|
||||
@@ -260,10 +253,10 @@ final class QuartzCronField extends CronField {
|
||||
int current = Type.DAY_OF_MONTH.get(temporal);
|
||||
DayOfWeek dayOfWeek = DayOfWeek.from(temporal);
|
||||
|
||||
if ((current == dayOfMonth && isWeekday(dayOfWeek)) || // dayOfMonth is a weekday
|
||||
(dayOfWeek == DayOfWeek.FRIDAY && current == dayOfMonth - 1) || // dayOfMonth is a Saturday, so Friday before
|
||||
(dayOfWeek == DayOfWeek.MONDAY && current == dayOfMonth + 1) || // dayOfMonth is a Sunday, so Monday after
|
||||
(dayOfWeek == DayOfWeek.MONDAY && dayOfMonth == 1 && current == 3)) { // dayOfMonth is Saturday 1st, so Monday 3rd
|
||||
if ((current == dayOfMonth && isWeekday(dayOfWeek)) || // dayOfMonth is a weekday
|
||||
(dayOfWeek == DayOfWeek.FRIDAY && current == dayOfMonth - 1) || // dayOfMonth is a Saturday, so Friday before
|
||||
(dayOfWeek == DayOfWeek.MONDAY && current == dayOfMonth + 1) || // dayOfMonth is a Sunday, so Monday after
|
||||
(dayOfWeek == DayOfWeek.MONDAY && dayOfMonth == 1 && current == 3)) { // dayOfMonth is Saturday 1st, so Monday 3rd
|
||||
return temporal;
|
||||
}
|
||||
int count = 0;
|
||||
@@ -299,7 +292,7 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a temporal adjuster that finds the last of the given day-of-week
|
||||
* Return a temporal adjuster that finds the last of the given doy-of-week
|
||||
* in a month.
|
||||
*/
|
||||
private static TemporalAdjuster lastInMonth(DayOfWeek dayOfWeek) {
|
||||
@@ -336,7 +329,6 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T extends Temporal & Comparable<? super T>> T nextOrSame(T temporal) {
|
||||
T result = adjust(temporal);
|
||||
@@ -353,6 +345,7 @@ final class QuartzCronField extends CronField {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends Temporal & Comparable<? super T>> T adjust(T temporal) {
|
||||
@@ -360,26 +353,28 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof QuartzCronField)) {
|
||||
return false;
|
||||
}
|
||||
QuartzCronField otherField = (QuartzCronField) other;
|
||||
return (type() == otherField.type() && this.value.equals(otherField.value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.value.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof QuartzCronField)) {
|
||||
return false;
|
||||
}
|
||||
QuartzCronField other = (QuartzCronField) o;
|
||||
return type() == other.type() &&
|
||||
this.value.equals(other.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type() + " '" + this.value + "'";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+44
-51
@@ -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.
|
||||
@@ -92,7 +92,7 @@ public class ProxyFactoryBeanTests {
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws Exception {
|
||||
public void setUp() throws Exception {
|
||||
DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
|
||||
parent.registerBeanDefinition("target2", new RootBeanDefinition(TestApplicationListener.class));
|
||||
this.factory = new DefaultListableBeanFactory(parent);
|
||||
@@ -139,24 +139,22 @@ public class ProxyFactoryBeanTests {
|
||||
private void testDoubleTargetSourceIsRejected(String name) {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(DBL_TARGETSOURCE_CONTEXT, CLASS));
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class).as("Should not allow TargetSource to be specified in interceptorNames as well as targetSource property")
|
||||
.isThrownBy(() -> bf.getBean(name))
|
||||
.havingCause()
|
||||
.isInstanceOf(AopConfigException.class)
|
||||
.withMessageContaining("TargetSource");
|
||||
.isThrownBy(() -> bf.getBean(name))
|
||||
.havingCause()
|
||||
.isInstanceOf(AopConfigException.class)
|
||||
.withMessageContaining("TargetSource");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTargetSourceNotAtEndOfInterceptorNamesIsRejected() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(NOTLAST_TARGETSOURCE_CONTEXT, CLASS));
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class).as("TargetSource or non-advised object must be last in interceptorNames")
|
||||
.isThrownBy(() -> bf.getBean("targetSourceNotLast"))
|
||||
.havingCause()
|
||||
.isInstanceOf(AopConfigException.class)
|
||||
.withMessageContaining("interceptorNames");
|
||||
.isThrownBy(() -> bf.getBean("targetSourceNotLast"))
|
||||
.havingCause()
|
||||
.isInstanceOf(AopConfigException.class)
|
||||
.withMessageContaining("interceptorNames");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -169,11 +167,11 @@ public class ProxyFactoryBeanTests {
|
||||
assertThat(cba.getCalls()).isEqualTo(0);
|
||||
|
||||
ITestBean tb = (ITestBean) bf.getBean("directTarget");
|
||||
assertThat(tb.getName()).isEqualTo("Adam");
|
||||
assertThat(tb.getName().equals("Adam")).isTrue();
|
||||
assertThat(cba.getCalls()).isEqualTo(1);
|
||||
|
||||
ProxyFactoryBean pfb = (ProxyFactoryBean) bf.getBean("&directTarget");
|
||||
assertThat(pfb.getObjectType()).isAssignableTo(TestBean.class);
|
||||
assertThat(TestBean.class.isAssignableFrom(pfb.getObjectType())).as("Has correct object type").isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -181,9 +179,9 @@ public class ProxyFactoryBeanTests {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(TARGETSOURCE_CONTEXT, CLASS));
|
||||
ITestBean tb = (ITestBean) bf.getBean("viaTargetSource");
|
||||
assertThat(tb.getName()).isEqualTo("Adam");
|
||||
assertThat(tb.getName().equals("Adam")).isTrue();
|
||||
ProxyFactoryBean pfb = (ProxyFactoryBean) bf.getBean("&viaTargetSource");
|
||||
assertThat(pfb.getObjectType()).isAssignableTo(TestBean.class);
|
||||
assertThat(TestBean.class.isAssignableFrom(pfb.getObjectType())).as("Has correct object type").isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -192,15 +190,11 @@ public class ProxyFactoryBeanTests {
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(TARGETSOURCE_CONTEXT, CLASS));
|
||||
|
||||
ITestBean tb = (ITestBean) bf.getBean("noTarget");
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(tb::getName).withMessage("getName");
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() ->
|
||||
tb.getName())
|
||||
.withMessage("getName");
|
||||
FactoryBean<?> pfb = (ProxyFactoryBean) bf.getBean("&noTarget");
|
||||
assertThat(pfb.getObjectType()).isAssignableTo(ITestBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetObjectTypeOnUninitializedFactoryBean() {
|
||||
ProxyFactoryBean pfb = new ProxyFactoryBean();
|
||||
assertThat(pfb.getObjectType()).isNull();
|
||||
assertThat(ITestBean.class.isAssignableFrom(pfb.getObjectType())).as("Has correct object type").isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,20 +219,20 @@ public class ProxyFactoryBeanTests {
|
||||
pc1.addAdvice(1, di);
|
||||
assertThat(pc2.getAdvisors()).isEqualTo(pc1.getAdvisors());
|
||||
assertThat(pc2.getAdvisors().length).as("Now have one more advisor").isEqualTo((oldLength + 1));
|
||||
assertThat(di.getCount()).isEqualTo(0);
|
||||
assertThat(0).isEqualTo(di.getCount());
|
||||
test1.setAge(5);
|
||||
assertThat(test1.getAge()).isEqualTo(test1_1.getAge());
|
||||
assertThat(di.getCount()).isEqualTo(3);
|
||||
assertThat(3).isEqualTo(di.getCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrototypeInstancesAreNotEqual() {
|
||||
assertThat(factory.getType("prototype")).isAssignableTo(ITestBean.class);
|
||||
assertThat(ITestBean.class.isAssignableFrom(factory.getType("prototype"))).as("Has correct object type").isTrue();
|
||||
ITestBean test2 = (ITestBean) factory.getBean("prototype");
|
||||
ITestBean test2_1 = (ITestBean) factory.getBean("prototype");
|
||||
assertThat(test2).as("Prototype instances !=").isNotSameAs(test2_1);
|
||||
assertThat(test2).as("Prototype instances equal").isEqualTo(test2_1);
|
||||
assertThat(factory.getType("prototype")).isAssignableTo(ITestBean.class);
|
||||
assertThat(test2 != test2_1).as("Prototype instances !=").isTrue();
|
||||
assertThat(test2.equals(test2_1)).as("Prototype instances equal").isTrue();
|
||||
assertThat(ITestBean.class.isAssignableFrom(factory.getType("prototype"))).as("Has correct object type").isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,7 +262,7 @@ public class ProxyFactoryBeanTests {
|
||||
assertThat(prototype2FirstInstance.getCount()).isEqualTo(INITIAL_COUNT + 1);
|
||||
|
||||
SideEffectBean prototype2SecondInstance = (SideEffectBean) bf.getBean(beanName);
|
||||
assertThat(prototype2FirstInstance).as("Prototypes are not ==").isNotSameAs(prototype2SecondInstance);
|
||||
assertThat(prototype2FirstInstance == prototype2SecondInstance).as("Prototypes are not ==").isFalse();
|
||||
assertThat(prototype2SecondInstance.getCount()).isEqualTo(INITIAL_COUNT);
|
||||
assertThat(prototype2FirstInstance.getCount()).isEqualTo(INITIAL_COUNT + 1);
|
||||
|
||||
@@ -291,19 +285,19 @@ public class ProxyFactoryBeanTests {
|
||||
TestBean target = (TestBean) factory.getBean("test");
|
||||
target.setName(name);
|
||||
ITestBean autoInvoker = (ITestBean) factory.getBean("autoInvoker");
|
||||
assertThat(autoInvoker.getName()).isEqualTo(name);
|
||||
assertThat(autoInvoker.getName().equals(name)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanGetFactoryReferenceAndManipulate() {
|
||||
ProxyFactoryBean config = (ProxyFactoryBean) factory.getBean("&test1");
|
||||
assertThat(config.getObjectType()).isAssignableTo(ITestBean.class);
|
||||
assertThat(factory.getType("test1")).isAssignableTo(ITestBean.class);
|
||||
assertThat(ITestBean.class.isAssignableFrom(config.getObjectType())).as("Has correct object type").isTrue();
|
||||
assertThat(ITestBean.class.isAssignableFrom(factory.getType("test1"))).as("Has correct object type").isTrue();
|
||||
// Trigger lazy initialization.
|
||||
config.getObject();
|
||||
assertThat(config.getAdvisors().length).as("Have one advisors").isEqualTo(1);
|
||||
assertThat(config.getObjectType()).isAssignableTo(ITestBean.class);
|
||||
assertThat(factory.getType("test1")).isAssignableTo(ITestBean.class);
|
||||
assertThat(ITestBean.class.isAssignableFrom(config.getObjectType())).as("Has correct object type").isTrue();
|
||||
assertThat(ITestBean.class.isAssignableFrom(factory.getType("test1"))).as("Has correct object type").isTrue();
|
||||
|
||||
ITestBean tb = (ITestBean) factory.getBean("test1");
|
||||
// no exception
|
||||
@@ -314,7 +308,7 @@ public class ProxyFactoryBeanTests {
|
||||
config.addAdvice(0, (MethodInterceptor) invocation -> {
|
||||
throw ex;
|
||||
});
|
||||
assertThat(config.getAdvisors()).as("Have correct advisor count").hasSize(2);
|
||||
assertThat(config.getAdvisors().length).as("Have correct advisor count").isEqualTo(2);
|
||||
|
||||
ITestBean tb1 = (ITestBean) factory.getBean("test1");
|
||||
assertThatException()
|
||||
@@ -354,31 +348,31 @@ public class ProxyFactoryBeanTests {
|
||||
// Add to head of interceptor chain
|
||||
int oldCount = config.getAdvisors().length;
|
||||
config.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class));
|
||||
assertThat(config.getAdvisors()).hasSize(oldCount + 1);
|
||||
assertThat(config.getAdvisors().length == oldCount + 1).isTrue();
|
||||
|
||||
TimeStamped ts = (TimeStamped) factory.getBean("test2");
|
||||
assertThat(ts.getTimeStamp()).isEqualTo(time);
|
||||
|
||||
// Can remove
|
||||
config.removeAdvice(ti);
|
||||
assertThat(config.getAdvisors()).hasSize(oldCount);
|
||||
assertThat(config.getAdvisors().length == oldCount).isTrue();
|
||||
|
||||
// Check no change on existing object reference
|
||||
assertThat(ts.getTimeStamp()).isEqualTo(time);
|
||||
assertThat(ts.getTimeStamp() == time).isTrue();
|
||||
|
||||
assertThat(factory.getBean("test2")).as("Should no longer implement TimeStamped")
|
||||
.isNotInstanceOf(TimeStamped.class);
|
||||
|
||||
// Now check non-effect of removing interceptor that isn't there
|
||||
config.removeAdvice(new DebugInterceptor());
|
||||
assertThat(config.getAdvisors()).hasSize(oldCount);
|
||||
assertThat(config.getAdvisors().length == oldCount).isTrue();
|
||||
|
||||
ITestBean it = (ITestBean) ts;
|
||||
DebugInterceptor debugInterceptor = new DebugInterceptor();
|
||||
config.addAdvice(0, debugInterceptor);
|
||||
it.getSpouse();
|
||||
// Won't affect existing reference
|
||||
assertThat(debugInterceptor.getCount()).isEqualTo(0);
|
||||
assertThat(debugInterceptor.getCount() == 0).isTrue();
|
||||
it = (ITestBean) factory.getBean("test2");
|
||||
it.getSpouse();
|
||||
assertThat(debugInterceptor.getCount()).isEqualTo(1);
|
||||
@@ -418,16 +412,16 @@ public class ProxyFactoryBeanTests {
|
||||
public void testMethodPointcuts() {
|
||||
ITestBean tb = (ITestBean) factory.getBean("pointcuts");
|
||||
PointcutForVoid.reset();
|
||||
assertThat(PointcutForVoid.methodNames).as("No methods intercepted").isEmpty();
|
||||
assertThat(PointcutForVoid.methodNames.isEmpty()).as("No methods intercepted").isTrue();
|
||||
tb.getAge();
|
||||
assertThat(PointcutForVoid.methodNames).as("Not void: shouldn't have intercepted").isEmpty();
|
||||
assertThat(PointcutForVoid.methodNames.isEmpty()).as("Not void: shouldn't have intercepted").isTrue();
|
||||
tb.setAge(1);
|
||||
tb.getAge();
|
||||
tb.setName("Tristan");
|
||||
tb.toString();
|
||||
assertThat(PointcutForVoid.methodNames).as("Recorded wrong number of invocations").hasSize(2);
|
||||
assertThat(PointcutForVoid.methodNames.get(0)).isEqualTo("setAge");
|
||||
assertThat(PointcutForVoid.methodNames.get(1)).isEqualTo("setName");
|
||||
assertThat(PointcutForVoid.methodNames.size()).as("Recorded wrong number of invocations").isEqualTo(2);
|
||||
assertThat(PointcutForVoid.methodNames.get(0).equals("setAge")).isTrue();
|
||||
assertThat(PointcutForVoid.methodNames.get(1).equals("setName")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -504,17 +498,17 @@ public class ProxyFactoryBeanTests {
|
||||
@Test
|
||||
public void testGlobalsCanAddAspectInterfaces() {
|
||||
AddedGlobalInterface agi = (AddedGlobalInterface) factory.getBean("autoInvoker");
|
||||
assertThat(agi.globalsAdded()).isEqualTo(-1);
|
||||
assertThat(agi.globalsAdded() == -1).isTrue();
|
||||
|
||||
ProxyFactoryBean pfb = (ProxyFactoryBean) factory.getBean("&validGlobals");
|
||||
// Trigger lazy initialization.
|
||||
pfb.getObject();
|
||||
// 2 globals + 2 explicit
|
||||
assertThat(pfb.getAdvisors()).as("Have 2 globals and 2 explicit advisors").hasSize(3);
|
||||
assertThat(pfb.getAdvisors().length).as("Have 2 globals and 2 explicit advisors").isEqualTo(3);
|
||||
|
||||
ApplicationListener<?> l = (ApplicationListener<?>) factory.getBean("validGlobals");
|
||||
agi = (AddedGlobalInterface) l;
|
||||
assertThat(agi.globalsAdded()).isEqualTo(-1);
|
||||
assertThat(agi.globalsAdded() == -1).isTrue();
|
||||
|
||||
assertThat(factory.getBean("test1")).as("Aspect interface shouldn't be implemented without globals")
|
||||
.isNotInstanceOf(AddedGlobalInterface.class);
|
||||
@@ -715,7 +709,6 @@ public class ProxyFactoryBeanTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Aspect interface
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
*/
|
||||
class ScopedProxyTests {
|
||||
public class ScopedProxyTests {
|
||||
|
||||
private static final Class<?> CLASS = ScopedProxyTests.class;
|
||||
private static final String CLASSNAME = CLASS.getSimpleName();
|
||||
@@ -51,24 +51,27 @@ class ScopedProxyTests {
|
||||
|
||||
|
||||
@Test // SPR-2108
|
||||
void testProxyAssignable() {
|
||||
public void testProxyAssignable() throws Exception {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(MAP_CONTEXT);
|
||||
Object baseMap = bf.getBean("singletonMap");
|
||||
assertThat(baseMap instanceof Map).isTrue();
|
||||
boolean condition = baseMap instanceof Map;
|
||||
assertThat(condition).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimpleProxy() {
|
||||
public void testSimpleProxy() throws Exception {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(MAP_CONTEXT);
|
||||
Object simpleMap = bf.getBean("simpleMap");
|
||||
assertThat(simpleMap instanceof Map).isTrue();
|
||||
assertThat(simpleMap instanceof HashMap).isTrue();
|
||||
boolean condition1 = simpleMap instanceof Map;
|
||||
assertThat(condition1).isTrue();
|
||||
boolean condition = simpleMap instanceof HashMap;
|
||||
assertThat(condition).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testScopedOverride() {
|
||||
public void testScopedOverride() throws Exception {
|
||||
GenericApplicationContext ctx = new GenericApplicationContext();
|
||||
new XmlBeanDefinitionReader(ctx).loadBeanDefinitions(OVERRIDE_CONTEXT);
|
||||
SimpleMapScope scope = new SimpleMapScope();
|
||||
@@ -84,7 +87,7 @@ class ScopedProxyTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJdkScopedProxy() throws Exception {
|
||||
public void testJdkScopedProxy() throws Exception {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(TESTBEAN_CONTEXT);
|
||||
bf.setSerializationId("X");
|
||||
@@ -94,7 +97,8 @@ class ScopedProxyTests {
|
||||
ITestBean bean = (ITestBean) bf.getBean("testBean");
|
||||
assertThat(bean).isNotNull();
|
||||
assertThat(AopUtils.isJdkDynamicProxy(bean)).isTrue();
|
||||
assertThat(bean instanceof ScopedObject).isTrue();
|
||||
boolean condition1 = bean instanceof ScopedObject;
|
||||
assertThat(condition1).isTrue();
|
||||
ScopedObject scoped = (ScopedObject) bean;
|
||||
assertThat(scoped.getTargetObject().getClass()).isEqualTo(TestBean.class);
|
||||
bean.setAge(101);
|
||||
@@ -106,7 +110,8 @@ class ScopedProxyTests {
|
||||
assertThat(deserialized).isNotNull();
|
||||
assertThat(AopUtils.isJdkDynamicProxy(deserialized)).isTrue();
|
||||
assertThat(bean.getAge()).isEqualTo(101);
|
||||
assertThat(deserialized instanceof ScopedObject).isTrue();
|
||||
boolean condition = deserialized instanceof ScopedObject;
|
||||
assertThat(condition).isTrue();
|
||||
ScopedObject scopedDeserialized = (ScopedObject) deserialized;
|
||||
assertThat(scopedDeserialized.getTargetObject().getClass()).isEqualTo(TestBean.class);
|
||||
|
||||
@@ -114,7 +119,7 @@ class ScopedProxyTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCglibScopedProxy() throws Exception {
|
||||
public void testCglibScopedProxy() throws Exception {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(LIST_CONTEXT);
|
||||
bf.setSerializationId("Y");
|
||||
@@ -123,7 +128,8 @@ class ScopedProxyTests {
|
||||
|
||||
TestBean tb = (TestBean) bf.getBean("testBean");
|
||||
assertThat(AopUtils.isCglibProxy(tb.getFriends())).isTrue();
|
||||
assertThat(tb.getFriends() instanceof ScopedObject).isTrue();
|
||||
boolean condition1 = tb.getFriends() instanceof ScopedObject;
|
||||
assertThat(condition1).isTrue();
|
||||
ScopedObject scoped = (ScopedObject) tb.getFriends();
|
||||
assertThat(scoped.getTargetObject().getClass()).isEqualTo(ArrayList.class);
|
||||
tb.getFriends().add("myFriend");
|
||||
@@ -131,11 +137,12 @@ class ScopedProxyTests {
|
||||
assertThat(scope.getMap().containsKey("scopedTarget.scopedList")).isTrue();
|
||||
assertThat(scope.getMap().get("scopedTarget.scopedList").getClass()).isEqualTo(ArrayList.class);
|
||||
|
||||
ArrayList<Object> deserialized = (ArrayList<Object>) SerializationTestUtils.serializeAndDeserialize(tb.getFriends());
|
||||
ArrayList<?> deserialized = (ArrayList<?>) SerializationTestUtils.serializeAndDeserialize(tb.getFriends());
|
||||
assertThat(deserialized).isNotNull();
|
||||
assertThat(AopUtils.isCglibProxy(deserialized)).isTrue();
|
||||
assertThat(deserialized).contains("myFriend");
|
||||
assertThat(deserialized instanceof ScopedObject).isTrue();
|
||||
assertThat(deserialized.contains("myFriend")).isTrue();
|
||||
boolean condition = deserialized instanceof ScopedObject;
|
||||
assertThat(condition).isTrue();
|
||||
ScopedObject scopedDeserialized = (ScopedObject) deserialized;
|
||||
assertThat(scopedDeserialized.getTargetObject().getClass()).isEqualTo(ArrayList.class);
|
||||
|
||||
|
||||
+52
-61
@@ -63,12 +63,12 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
new RootBeanDefinition(QualifiedFieldTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -81,13 +81,12 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -101,10 +100,9 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -207,13 +205,12 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedFieldTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -230,13 +227,12 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -253,10 +249,9 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -379,13 +374,12 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -457,13 +451,12 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -514,13 +507,12 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -582,10 +574,9 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
|
||||
}
|
||||
|
||||
|
||||
@@ -761,7 +752,7 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
@Qualifier
|
||||
@interface TestQualifierWithMultipleAttributes {
|
||||
|
||||
String[] value() default "default";
|
||||
String value() default "default";
|
||||
|
||||
int number();
|
||||
}
|
||||
|
||||
+6
-8
@@ -58,10 +58,9 @@ public class QualifierAnnotationTests {
|
||||
BeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
|
||||
reader.loadBeanDefinitions(CONFIG_LOCATION);
|
||||
context.registerSingleton("testBean", NonQualifiedTestBean.class);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.withMessageContaining("found 6");
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.withMessageContaining("found 6");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -192,10 +191,9 @@ public class QualifierAnnotationTests {
|
||||
BeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
|
||||
reader.loadBeanDefinitions(CONFIG_LOCATION);
|
||||
context.registerSingleton("testBean", QualifiedByAttributesTestBean.class);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.withMessageContaining("found 6");
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.withMessageContaining("found 6");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+3
-22
@@ -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.
|
||||
@@ -215,7 +215,7 @@ public class CommonAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("testBean4", tbd);
|
||||
|
||||
bf.registerResolvableDependency(BeanFactory.class, bf);
|
||||
bf.registerResolvableDependency(INestedTestBean.class, (ObjectFactory<Object>) NestedTestBean::new);
|
||||
bf.registerResolvableDependency(INestedTestBean.class, (ObjectFactory<Object>) () -> new NestedTestBean());
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
org.springframework.beans.factory.config.PropertyPlaceholderConfigurer ppc = new org.springframework.beans.factory.config.PropertyPlaceholderConfigurer();
|
||||
@@ -233,7 +233,7 @@ public class CommonAnnotationBeanPostProcessorTests {
|
||||
assertThat(tb).isNotSameAs(anotherBean.getTestBean6());
|
||||
|
||||
String[] depBeans = bf.getDependenciesForBean("annotatedBean");
|
||||
assertThat(depBeans).hasSize(1);
|
||||
assertThat(depBeans.length).isEqualTo(1);
|
||||
assertThat(depBeans[0]).isEqualTo("testBean4");
|
||||
}
|
||||
|
||||
@@ -508,25 +508,6 @@ public class CommonAnnotationBeanPostProcessorTests {
|
||||
assertThat(tb.getName()).isEqualTo("notLazyAnymore");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyResolutionWithFallbackTypeMatch() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
|
||||
CommonAnnotationBeanPostProcessor bpp = new CommonAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(LazyResourceCglibInjectionBean.class));
|
||||
bf.registerBeanDefinition("tb", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
LazyResourceCglibInjectionBean bean = (LazyResourceCglibInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bf.containsSingleton("tb")).isFalse();
|
||||
bean.testBean.setName("notLazyAnymore");
|
||||
assertThat(bf.containsSingleton("tb")).isTrue();
|
||||
TestBean tb = (TestBean) bf.getBean("tb");
|
||||
assertThat(tb.getName()).isEqualTo("notLazyAnymore");
|
||||
}
|
||||
|
||||
|
||||
public static class AnnotatedInitDestroyBean {
|
||||
|
||||
|
||||
+7
-7
@@ -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.
|
||||
@@ -138,8 +138,8 @@ class PropertySourceAnnotationTests {
|
||||
@Test
|
||||
void withUnresolvablePlaceholder() {
|
||||
assertThatExceptionOfType(BeanDefinitionStoreException.class)
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithUnresolvablePlaceholder.class))
|
||||
.withCauseInstanceOf(IllegalArgumentException.class);
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithUnresolvablePlaceholder.class))
|
||||
.withCauseInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -170,8 +170,8 @@ class PropertySourceAnnotationTests {
|
||||
@Test
|
||||
void withEmptyResourceLocations() {
|
||||
assertThatExceptionOfType(BeanDefinitionStoreException.class)
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithEmptyResourceLocations.class))
|
||||
.withCauseInstanceOf(IllegalArgumentException.class);
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithEmptyResourceLocations.class))
|
||||
.withCauseInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -253,8 +253,8 @@ class PropertySourceAnnotationTests {
|
||||
@Test
|
||||
void withMissingPropertySource() {
|
||||
assertThatExceptionOfType(BeanDefinitionStoreException.class)
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithMissingPropertySource.class))
|
||||
.withCauseInstanceOf(FileNotFoundException.class);
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithMissingPropertySource.class))
|
||||
.withCauseInstanceOf(FileNotFoundException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+8
-16
@@ -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.
|
||||
@@ -36,10 +36,6 @@ public abstract class AbstractApplicationEventListenerTests {
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> GenericTestEvent<T> createGenericTestEvent(T payload) {
|
||||
return new GenericTestEvent<>(this, payload);
|
||||
}
|
||||
|
||||
|
||||
protected static class GenericTestEvent<T> extends ApplicationEvent {
|
||||
|
||||
@@ -55,7 +51,6 @@ public abstract class AbstractApplicationEventListenerTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected static class SmartGenericTestEvent<T> extends GenericTestEvent<T> implements ResolvableTypeProvider {
|
||||
|
||||
private final ResolvableType resolvableType;
|
||||
@@ -72,7 +67,6 @@ public abstract class AbstractApplicationEventListenerTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected static class StringEvent extends GenericTestEvent<String> {
|
||||
|
||||
public StringEvent(Object source, String payload) {
|
||||
@@ -80,7 +74,6 @@ public abstract class AbstractApplicationEventListenerTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected static class LongEvent extends GenericTestEvent<Long> {
|
||||
|
||||
public LongEvent(Object source, Long payload) {
|
||||
@@ -88,31 +81,31 @@ public abstract class AbstractApplicationEventListenerTests {
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> GenericTestEvent<T> createGenericTestEvent(T payload) {
|
||||
return new GenericTestEvent<>(this, payload);
|
||||
}
|
||||
|
||||
|
||||
static class GenericEventListener implements ApplicationListener<GenericTestEvent<?>> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(GenericTestEvent<?> event) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class ObjectEventListener implements ApplicationListener<GenericTestEvent<Object>> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(GenericTestEvent<Object> event) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class UpperBoundEventListener implements ApplicationListener<GenericTestEvent<? extends RuntimeException>> {
|
||||
static class UpperBoundEventListener
|
||||
implements ApplicationListener<GenericTestEvent<? extends RuntimeException>> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(GenericTestEvent<? extends RuntimeException> event) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class StringEventListener implements ApplicationListener<GenericTestEvent<String>> {
|
||||
|
||||
@Override
|
||||
@@ -120,7 +113,6 @@ public abstract class AbstractApplicationEventListenerTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
static class RawApplicationListener implements ApplicationListener {
|
||||
|
||||
@@ -129,10 +121,10 @@ public abstract class AbstractApplicationEventListenerTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class TestEvents {
|
||||
|
||||
public GenericTestEvent<?> wildcardEvent;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-3
@@ -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.
|
||||
@@ -104,8 +104,7 @@ public class GenericApplicationListenerAdapterTests extends AbstractApplicationE
|
||||
|
||||
@Test
|
||||
public void genericListenerStrictTypeSubClass() {
|
||||
supportsEventType(false, ObjectEventListener.class,
|
||||
ResolvableType.forClassWithGenerics(GenericTestEvent.class, Long.class));
|
||||
supportsEventType(false, ObjectEventListener.class, ResolvableType.forClassWithGenerics(GenericTestEvent.class, Long.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+5
-5
@@ -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.
|
||||
@@ -102,16 +102,16 @@ class GenericApplicationContextTests {
|
||||
|
||||
assertThat(context.getBean(String.class)).isSameAs(context.getBean("testBean"));
|
||||
assertThat(context.getAutowireCapableBeanFactory().getBean(String.class))
|
||||
.isSameAs(context.getAutowireCapableBeanFactory().getBean("testBean"));
|
||||
.isSameAs(context.getAutowireCapableBeanFactory().getBean("testBean"));
|
||||
|
||||
context.close();
|
||||
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> context.getBean(String.class));
|
||||
.isThrownBy(() -> context.getBean(String.class));
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> context.getAutowireCapableBeanFactory().getBean(String.class));
|
||||
.isThrownBy(() -> context.getAutowireCapableBeanFactory().getBean(String.class));
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> context.getAutowireCapableBeanFactory().getBean("testBean"));
|
||||
.isThrownBy(() -> context.getAutowireCapableBeanFactory().getBean("testBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+8
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -35,32 +35,27 @@ class BitsCronFieldTests {
|
||||
@Test
|
||||
void parse() {
|
||||
assertThat(BitsCronField.parseSeconds("42")).has(clearRange(0, 41)).has(set(42)).has(clearRange(43, 59));
|
||||
assertThat(BitsCronField.parseSeconds("0-4,8-12")).has(setRange(0, 4)).has(clearRange(5,7))
|
||||
.has(setRange(8, 12)).has(clearRange(13,59));
|
||||
assertThat(BitsCronField.parseSeconds("57/2")).has(clearRange(0, 56)).has(set(57))
|
||||
.has(clear(58)).has(set(59));
|
||||
assertThat(BitsCronField.parseSeconds("0-4,8-12")).has(setRange(0, 4)).has(clearRange(5,7)).has(setRange(8, 12)).has(clearRange(13,59));
|
||||
assertThat(BitsCronField.parseSeconds("57/2")).has(clearRange(0, 56)).has(set(57)).has(clear(58)).has(set(59));
|
||||
|
||||
assertThat(BitsCronField.parseMinutes("30")).has(set(30)).has(clearRange(1, 29)).has(clearRange(31, 59));
|
||||
|
||||
assertThat(BitsCronField.parseHours("23")).has(set(23)).has(clearRange(0, 23));
|
||||
assertThat(BitsCronField.parseHours("0-23/2")).has(set(0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22))
|
||||
.has(clear(1,3,5,7,9,11,13,15,17,19,21,23));
|
||||
assertThat(BitsCronField.parseHours("0-23/2")).has(set(0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22)).has(clear(1,3,5,7,9,11,13,15,17,19,21,23));
|
||||
|
||||
assertThat(BitsCronField.parseDaysOfMonth("1")).has(set(1)).has(clearRange(2, 31));
|
||||
|
||||
assertThat(BitsCronField.parseMonth("1")).has(set(1)).has(clearRange(2, 12));
|
||||
|
||||
assertThat(BitsCronField.parseDaysOfWeek("0")).has(set(7, 7)).has(clearRange(0, 6));
|
||||
assertThat(BitsCronField.parseDaysOfWeek("7-5")).has(clear(0)).has(setRange(1, 5))
|
||||
.has(clear(6)).has(set(7));
|
||||
|
||||
assertThat(BitsCronField.parseDaysOfWeek("7-5")).has(clear(0)).has(setRange(1, 5)).has(clear(6)).has(set(7));
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseLists() {
|
||||
assertThat(BitsCronField.parseSeconds("15,30")).has(set(15, 30)).has(clearRange(1, 15))
|
||||
.has(clearRange(31, 59));
|
||||
assertThat(BitsCronField.parseMinutes("1,2,5,9")).has(set(1, 2, 5, 9)).has(clear(0))
|
||||
.has(clearRange(3, 4)).has(clearRange(6, 8)).has(clearRange(10, 59));
|
||||
assertThat(BitsCronField.parseSeconds("15,30")).has(set(15, 30)).has(clearRange(1, 15)).has(clearRange(31, 59));
|
||||
assertThat(BitsCronField.parseMinutes("1,2,5,9")).has(set(1, 2, 5, 9)).has(clear(0)).has(clearRange(3, 4)).has(clearRange(6, 8)).has(clearRange(10, 59));
|
||||
assertThat(BitsCronField.parseHours("1,2,3")).has(set(1, 2, 3)).has(clearRange(4, 23));
|
||||
assertThat(BitsCronField.parseDaysOfMonth("1,2,3")).has(set(1, 2, 3)).has(clearRange(4, 31));
|
||||
assertThat(BitsCronField.parseMonth("1,2,3")).has(set(1, 2, 3)).has(clearRange(4, 12));
|
||||
@@ -112,7 +107,6 @@ class BitsCronFieldTests {
|
||||
.has(clear(0)).has(setRange(1, 7));
|
||||
}
|
||||
|
||||
|
||||
private static Condition<BitsCronField> set(int... indices) {
|
||||
return new Condition<BitsCronField>(String.format("set bits %s", Arrays.toString(indices))) {
|
||||
@Override
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -848,7 +848,6 @@ class CronTriggerTests {
|
||||
assertThat(nextExecutionTime).isEqualTo(this.calendar.getTime());
|
||||
}
|
||||
|
||||
|
||||
private static void roundup(Calendar calendar) {
|
||||
calendar.add(Calendar.SECOND, 1);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
@@ -862,7 +861,9 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
private static TriggerContext getTriggerContext(Date lastCompletionTime) {
|
||||
return new SimpleTriggerContext(null, null, lastCompletionTime);
|
||||
SimpleTriggerContext context = new SimpleTriggerContext();
|
||||
context.update(null, null, lastCompletionTime);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-42
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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,7 +28,6 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
* Unit tests for {@link QuartzCronField}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
class QuartzCronFieldTests {
|
||||
|
||||
@@ -72,46 +71,6 @@ class QuartzCronFieldTests {
|
||||
assertThat(field.nextOrSame(last)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void dayOfWeek_0(){
|
||||
// third Sunday (0) of the month
|
||||
QuartzCronField field = QuartzCronField.parseDaysOfWeek("0#3");
|
||||
|
||||
LocalDate last = LocalDate.of(2024, 1, 1);
|
||||
LocalDate expected = LocalDate.of(2024, 1, 21);
|
||||
assertThat(field.nextOrSame(last)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void dayOfWeek_1(){
|
||||
// third Monday (1) of the month
|
||||
QuartzCronField field = QuartzCronField.parseDaysOfWeek("1#3");
|
||||
|
||||
LocalDate last = LocalDate.of(2024, 1, 1);
|
||||
LocalDate expected = LocalDate.of(2024, 1, 15);
|
||||
assertThat(field.nextOrSame(last)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void dayOfWeek_2(){
|
||||
// third Tuesday (2) of the month
|
||||
QuartzCronField field = QuartzCronField.parseDaysOfWeek("2#3");
|
||||
|
||||
LocalDate last = LocalDate.of(2024, 1, 1);
|
||||
LocalDate expected = LocalDate.of(2024, 1, 16);
|
||||
assertThat(field.nextOrSame(last)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void dayOfWeek_7() {
|
||||
// third Sunday (7 as alternative to 0) of the month
|
||||
QuartzCronField field = QuartzCronField.parseDaysOfWeek("7#3");
|
||||
|
||||
LocalDate last = LocalDate.of(2024, 1, 1);
|
||||
LocalDate expected = LocalDate.of(2024, 1, 21);
|
||||
assertThat(field.nextOrSame(last)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidValues() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfMonth(""));
|
||||
|
||||
+21
-12
@@ -3,6 +3,9 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<!--
|
||||
Not yet in use: illustration of possible approach
|
||||
-->
|
||||
<bean id="overrideOneMethod" class="org.springframework.beans.factory.xml.OverrideOneMethod">
|
||||
|
||||
<lookup-method name="getPrototypeDependency" bean="jenny"/>
|
||||
@@ -24,34 +27,39 @@
|
||||
|
||||
<lookup-method name="protectedOverrideSingleton" bean="david"/>
|
||||
|
||||
<!-- This method is not overloaded, so we don't need to specify any arg types -->
|
||||
<!--
|
||||
This method is not overloaded, so we don't need to specify any arg types
|
||||
-->
|
||||
<replaced-method name="doSomething" replacer="doSomethingReplacer"/>
|
||||
|
||||
</bean>
|
||||
|
||||
<bean id="replaceVoidMethod" parent="someParent" class="org.springframework.beans.factory.xml.OverrideOneMethodSubclass"/>
|
||||
<bean id="replaceVoidMethod" parent="someParent"
|
||||
class="org.springframework.beans.factory.xml.OverrideOneMethodSubclass">
|
||||
|
||||
<bean id="replaceEchoMethod" class="org.springframework.beans.factory.xml.EchoService">
|
||||
<!-- This method is not overloaded, so we don't need to specify any arg types -->
|
||||
<replaced-method name="echo" replacer="reverseArrayReplacer" />
|
||||
</bean>
|
||||
|
||||
<bean id="reverseReplacer" class="org.springframework.beans.factory.xml.ReverseMethodReplacer"/>
|
||||
<bean id="reverseReplacer"
|
||||
class="org.springframework.beans.factory.xml.ReverseMethodReplacer"/>
|
||||
|
||||
<bean id="reverseArrayReplacer" class="org.springframework.beans.factory.xml.ReverseArrayMethodReplacer"/>
|
||||
<bean id="fixedReplacer"
|
||||
class="org.springframework.beans.factory.xml.FixedMethodReplacer"/>
|
||||
|
||||
<bean id="fixedReplacer" class="org.springframework.beans.factory.xml.FixedMethodReplacer"/>
|
||||
<bean id="doSomethingReplacer"
|
||||
class="org.springframework.beans.factory.xml.XmlBeanFactoryTests$DoSomethingReplacer"/>
|
||||
|
||||
<bean id="doSomethingReplacer" class="org.springframework.beans.factory.xml.XmlBeanFactoryTests$DoSomethingReplacer"/>
|
||||
<bean id="serializableReplacer"
|
||||
class="org.springframework.beans.factory.xml.SerializableMethodReplacerCandidate">
|
||||
|
||||
<bean id="serializableReplacer" class="org.springframework.beans.factory.xml.SerializableMethodReplacerCandidate">
|
||||
<!-- Arbitrary method replacer -->
|
||||
<replaced-method name="replaceMe" replacer="reverseReplacer">
|
||||
<arg-type>String</arg-type>
|
||||
</replaced-method>
|
||||
|
||||
</bean>
|
||||
|
||||
<bean id="jenny" class="org.springframework.beans.testfixture.beans.TestBean" scope="prototype">
|
||||
<bean id="jenny" class="org.springframework.beans.testfixture.beans.TestBean"
|
||||
scope="prototype">
|
||||
<property name="name"><value>Jenny</value></property>
|
||||
<property name="age"><value>30</value></property>
|
||||
<property name="spouse">
|
||||
@@ -60,7 +68,8 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="david" class="org.springframework.beans.testfixture.beans.TestBean" scope="singleton">
|
||||
<bean id="david" class="org.springframework.beans.testfixture.beans.TestBean"
|
||||
scope="singleton">
|
||||
<description>
|
||||
Simple bean, without any collections.
|
||||
</description>
|
||||
|
||||
@@ -16,24 +16,12 @@
|
||||
package org.springframework.cglib.beans;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.*;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.cglib.core.AbstractClassGenerator;
|
||||
import org.springframework.cglib.core.ClassEmitter;
|
||||
import org.springframework.cglib.core.CodeEmitter;
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.cglib.core.Converter;
|
||||
import org.springframework.cglib.core.EmitUtils;
|
||||
import org.springframework.cglib.core.KeyFactory;
|
||||
import org.springframework.cglib.core.Local;
|
||||
import org.springframework.cglib.core.MethodInfo;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
import org.springframework.cglib.core.Signature;
|
||||
import org.springframework.cglib.core.TypeUtils;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Chris Nokleberg
|
||||
@@ -41,154 +29,151 @@ import org.springframework.cglib.core.TypeUtils;
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class BeanCopier
|
||||
{
|
||||
private static final BeanCopierKey KEY_FACTORY =
|
||||
(BeanCopierKey)KeyFactory.create(BeanCopierKey.class);
|
||||
private static final Type CONVERTER =
|
||||
TypeUtils.parseType("org.springframework.cglib.core.Converter");
|
||||
private static final Type BEAN_COPIER =
|
||||
TypeUtils.parseType("org.springframework.cglib.beans.BeanCopier");
|
||||
private static final Signature COPY =
|
||||
new Signature("copy", Type.VOID_TYPE, new Type[]{ Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER });
|
||||
private static final Signature CONVERT =
|
||||
TypeUtils.parseSignature("Object convert(Object, Class, Object)");
|
||||
private static final BeanCopierKey KEY_FACTORY =
|
||||
(BeanCopierKey)KeyFactory.create(BeanCopierKey.class);
|
||||
private static final Type CONVERTER =
|
||||
TypeUtils.parseType("org.springframework.cglib.core.Converter");
|
||||
private static final Type BEAN_COPIER =
|
||||
TypeUtils.parseType("org.springframework.cglib.beans.BeanCopier");
|
||||
private static final Signature COPY =
|
||||
new Signature("copy", Type.VOID_TYPE, new Type[]{ Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER });
|
||||
private static final Signature CONVERT =
|
||||
TypeUtils.parseSignature("Object convert(Object, Class, Object)");
|
||||
|
||||
interface BeanCopierKey {
|
||||
public Object newInstance(String source, String target, boolean useConverter);
|
||||
}
|
||||
|
||||
interface BeanCopierKey {
|
||||
public Object newInstance(String source, String target, boolean useConverter);
|
||||
}
|
||||
public static BeanCopier create(Class source, Class target, boolean useConverter) {
|
||||
Generator gen = new Generator();
|
||||
gen.setSource(source);
|
||||
gen.setTarget(target);
|
||||
gen.setUseConverter(useConverter);
|
||||
return gen.create();
|
||||
}
|
||||
|
||||
public static BeanCopier create(Class source, Class target, boolean useConverter) {
|
||||
Generator gen = new Generator();
|
||||
gen.setSource(source);
|
||||
gen.setTarget(target);
|
||||
gen.setUseConverter(useConverter);
|
||||
return gen.create();
|
||||
}
|
||||
abstract public void copy(Object from, Object to, Converter converter);
|
||||
|
||||
abstract public void copy(Object from, Object to, Converter converter);
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(BeanCopier.class.getName());
|
||||
private Class source;
|
||||
private Class target;
|
||||
private boolean useConverter;
|
||||
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(BeanCopier.class.getName());
|
||||
private Class source;
|
||||
private Class target;
|
||||
private boolean useConverter;
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
public void setSource(Class source) {
|
||||
this.source = source;
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(source);
|
||||
setNamePrefix(source.getName());
|
||||
// SPRING PATCH END
|
||||
}
|
||||
|
||||
public void setTarget(Class target) {
|
||||
this.target = target;
|
||||
public void setSource(Class source) {
|
||||
if(!Modifier.isPublic(source.getModifiers())){
|
||||
setNamePrefix(source.getName());
|
||||
}
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public void setTarget(Class target) {
|
||||
if(!Modifier.isPublic(target.getModifiers())){
|
||||
setNamePrefix(target.getName());
|
||||
}
|
||||
this.target = target;
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(target);
|
||||
setNamePrefix(target.getName());
|
||||
// SPRING PATCH END
|
||||
}
|
||||
}
|
||||
|
||||
public void setUseConverter(boolean useConverter) {
|
||||
this.useConverter = useConverter;
|
||||
}
|
||||
public void setUseConverter(boolean useConverter) {
|
||||
this.useConverter = useConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return source.getClassLoader();
|
||||
}
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return source.getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(source);
|
||||
}
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(source);
|
||||
}
|
||||
|
||||
public BeanCopier create() {
|
||||
Object key = KEY_FACTORY.newInstance(source.getName(), target.getName(), useConverter);
|
||||
return (BeanCopier)super.create(key);
|
||||
}
|
||||
public BeanCopier create() {
|
||||
Object key = KEY_FACTORY.newInstance(source.getName(), target.getName(), useConverter);
|
||||
return (BeanCopier)super.create(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateClass(ClassVisitor v) {
|
||||
Type sourceType = Type.getType(source);
|
||||
Type targetType = Type.getType(target);
|
||||
ClassEmitter ce = new ClassEmitter(v);
|
||||
ce.begin_class(Constants.V1_8,
|
||||
Constants.ACC_PUBLIC,
|
||||
getClassName(),
|
||||
BEAN_COPIER,
|
||||
null,
|
||||
Constants.SOURCE_FILE);
|
||||
public void generateClass(ClassVisitor v) {
|
||||
Type sourceType = Type.getType(source);
|
||||
Type targetType = Type.getType(target);
|
||||
ClassEmitter ce = new ClassEmitter(v);
|
||||
ce.begin_class(Constants.V1_8,
|
||||
Constants.ACC_PUBLIC,
|
||||
getClassName(),
|
||||
BEAN_COPIER,
|
||||
null,
|
||||
Constants.SOURCE_FILE);
|
||||
|
||||
EmitUtils.null_constructor(ce);
|
||||
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null);
|
||||
PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(source);
|
||||
PropertyDescriptor[] setters = ReflectUtils.getBeanSetters(target);
|
||||
EmitUtils.null_constructor(ce);
|
||||
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null);
|
||||
PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(source);
|
||||
PropertyDescriptor[] setters = ReflectUtils.getBeanSetters(target);
|
||||
|
||||
Map names = new HashMap();
|
||||
for (PropertyDescriptor getter : getters) {
|
||||
names.put(getter.getName(), getter);
|
||||
}
|
||||
Local targetLocal = e.make_local();
|
||||
Local sourceLocal = e.make_local();
|
||||
if (useConverter) {
|
||||
e.load_arg(1);
|
||||
e.checkcast(targetType);
|
||||
e.store_local(targetLocal);
|
||||
e.load_arg(0);
|
||||
e.checkcast(sourceType);
|
||||
e.store_local(sourceLocal);
|
||||
} else {
|
||||
e.load_arg(1);
|
||||
e.checkcast(targetType);
|
||||
e.load_arg(0);
|
||||
e.checkcast(sourceType);
|
||||
}
|
||||
for (PropertyDescriptor setter : setters) {
|
||||
PropertyDescriptor getter = (PropertyDescriptor)names.get(setter.getName());
|
||||
if (getter != null) {
|
||||
MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod());
|
||||
MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod());
|
||||
if (useConverter) {
|
||||
Type setterType = write.getSignature().getArgumentTypes()[0];
|
||||
e.load_local(targetLocal);
|
||||
e.load_arg(2);
|
||||
e.load_local(sourceLocal);
|
||||
e.invoke(read);
|
||||
e.box(read.getSignature().getReturnType());
|
||||
EmitUtils.load_class(e, setterType);
|
||||
e.push(write.getSignature().getName());
|
||||
e.invoke_interface(CONVERTER, CONVERT);
|
||||
e.unbox_or_zero(setterType);
|
||||
e.invoke(write);
|
||||
} else if (compatible(getter, setter)) {
|
||||
e.dup2();
|
||||
e.invoke(read);
|
||||
e.invoke(write);
|
||||
}
|
||||
}
|
||||
}
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
ce.end_class();
|
||||
}
|
||||
Map names = new HashMap();
|
||||
for (int i = 0; i < getters.length; i++) {
|
||||
names.put(getters[i].getName(), getters[i]);
|
||||
}
|
||||
Local targetLocal = e.make_local();
|
||||
Local sourceLocal = e.make_local();
|
||||
if (useConverter) {
|
||||
e.load_arg(1);
|
||||
e.checkcast(targetType);
|
||||
e.store_local(targetLocal);
|
||||
e.load_arg(0);
|
||||
e.checkcast(sourceType);
|
||||
e.store_local(sourceLocal);
|
||||
} else {
|
||||
e.load_arg(1);
|
||||
e.checkcast(targetType);
|
||||
e.load_arg(0);
|
||||
e.checkcast(sourceType);
|
||||
}
|
||||
for (int i = 0; i < setters.length; i++) {
|
||||
PropertyDescriptor setter = setters[i];
|
||||
PropertyDescriptor getter = (PropertyDescriptor)names.get(setter.getName());
|
||||
if (getter != null) {
|
||||
MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod());
|
||||
MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod());
|
||||
if (useConverter) {
|
||||
Type setterType = write.getSignature().getArgumentTypes()[0];
|
||||
e.load_local(targetLocal);
|
||||
e.load_arg(2);
|
||||
e.load_local(sourceLocal);
|
||||
e.invoke(read);
|
||||
e.box(read.getSignature().getReturnType());
|
||||
EmitUtils.load_class(e, setterType);
|
||||
e.push(write.getSignature().getName());
|
||||
e.invoke_interface(CONVERTER, CONVERT);
|
||||
e.unbox_or_zero(setterType);
|
||||
e.invoke(write);
|
||||
} else if (compatible(getter, setter)) {
|
||||
e.dup2();
|
||||
e.invoke(read);
|
||||
e.invoke(write);
|
||||
}
|
||||
}
|
||||
}
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
ce.end_class();
|
||||
}
|
||||
|
||||
private static boolean compatible(PropertyDescriptor getter, PropertyDescriptor setter) {
|
||||
// TODO: allow automatic widening conversions?
|
||||
return setter.getPropertyType().isAssignableFrom(getter.getPropertyType());
|
||||
}
|
||||
private static boolean compatible(PropertyDescriptor getter, PropertyDescriptor setter) {
|
||||
// TODO: allow automatic widening conversions?
|
||||
return setter.getPropertyType().isAssignableFrom(getter.getPropertyType());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object firstInstance(Class type) {
|
||||
return ReflectUtils.newInstance(type);
|
||||
}
|
||||
protected Object firstInstance(Class type) {
|
||||
return ReflectUtils.newInstance(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object nextInstance(Object instance) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
protected Object nextInstance(Object instance) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,18 +17,10 @@ package org.springframework.cglib.beans;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.cglib.core.AbstractClassGenerator;
|
||||
import org.springframework.cglib.core.ClassEmitter;
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.cglib.core.EmitUtils;
|
||||
import org.springframework.cglib.core.KeyFactory;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
|
||||
/**
|
||||
* @author Juozas Baliuka, Chris Nokleberg
|
||||
@@ -36,131 +28,126 @@ import org.springframework.cglib.core.ReflectUtils;
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class BeanGenerator extends AbstractClassGenerator
|
||||
{
|
||||
private static final Source SOURCE = new Source(BeanGenerator.class.getName());
|
||||
private static final BeanGeneratorKey KEY_FACTORY =
|
||||
(BeanGeneratorKey)KeyFactory.create(BeanGeneratorKey.class);
|
||||
private static final Source SOURCE = new Source(BeanGenerator.class.getName());
|
||||
private static final BeanGeneratorKey KEY_FACTORY =
|
||||
(BeanGeneratorKey)KeyFactory.create(BeanGeneratorKey.class);
|
||||
|
||||
interface BeanGeneratorKey {
|
||||
public Object newInstance(String superclass, Map props);
|
||||
}
|
||||
|
||||
interface BeanGeneratorKey {
|
||||
public Object newInstance(String superclass, Map props);
|
||||
}
|
||||
private Class superclass;
|
||||
private Map props = new HashMap();
|
||||
private boolean classOnly;
|
||||
|
||||
private Class superclass;
|
||||
private Map props = new HashMap();
|
||||
private boolean classOnly;
|
||||
public BeanGenerator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
public BeanGenerator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class which the generated class will extend. The class
|
||||
* must not be declared as final, and must have a non-private
|
||||
* no-argument constructor.
|
||||
* @param superclass class to extend, or null to extend Object
|
||||
*/
|
||||
public void setSuperclass(Class superclass) {
|
||||
if (superclass != null && superclass.equals(Object.class)) {
|
||||
superclass = null;
|
||||
}
|
||||
this.superclass = superclass;
|
||||
/**
|
||||
* Set the class which the generated class will extend. The class
|
||||
* must not be declared as final, and must have a non-private
|
||||
* no-argument constructor.
|
||||
* @param superclass class to extend, or null to extend Object
|
||||
*/
|
||||
public void setSuperclass(Class superclass) {
|
||||
if (superclass != null && superclass.equals(Object.class)) {
|
||||
superclass = null;
|
||||
}
|
||||
this.superclass = superclass;
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(superclass);
|
||||
// SPRING PATCH END
|
||||
}
|
||||
}
|
||||
|
||||
public void addProperty(String name, Class type) {
|
||||
if (props.containsKey(name)) {
|
||||
throw new IllegalArgumentException("Duplicate property name \"" + name + "\"");
|
||||
}
|
||||
props.put(name, Type.getType(type));
|
||||
}
|
||||
public void addProperty(String name, Class type) {
|
||||
if (props.containsKey(name)) {
|
||||
throw new IllegalArgumentException("Duplicate property name \"" + name + "\"");
|
||||
}
|
||||
props.put(name, Type.getType(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
if (superclass != null) {
|
||||
return superclass.getClassLoader();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
if (superclass != null) {
|
||||
return superclass.getClassLoader();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(superclass);
|
||||
}
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(superclass);
|
||||
}
|
||||
|
||||
public Object create() {
|
||||
classOnly = false;
|
||||
return createHelper();
|
||||
}
|
||||
public Object create() {
|
||||
classOnly = false;
|
||||
return createHelper();
|
||||
}
|
||||
|
||||
public Object createClass() {
|
||||
classOnly = true;
|
||||
return createHelper();
|
||||
}
|
||||
public Object createClass() {
|
||||
classOnly = true;
|
||||
return createHelper();
|
||||
}
|
||||
|
||||
private Object createHelper() {
|
||||
if (superclass != null) {
|
||||
setNamePrefix(superclass.getName());
|
||||
}
|
||||
String superName = (superclass != null) ? superclass.getName() : "java.lang.Object";
|
||||
Object key = KEY_FACTORY.newInstance(superName, props);
|
||||
return super.create(key);
|
||||
}
|
||||
private Object createHelper() {
|
||||
if (superclass != null) {
|
||||
setNamePrefix(superclass.getName());
|
||||
}
|
||||
String superName = (superclass != null) ? superclass.getName() : "java.lang.Object";
|
||||
Object key = KEY_FACTORY.newInstance(superName, props);
|
||||
return super.create(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateClass(ClassVisitor v) throws Exception {
|
||||
int size = props.size();
|
||||
String[] names = (String[])props.keySet().toArray(new String[size]);
|
||||
Type[] types = new Type[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
types[i] = (Type)props.get(names[i]);
|
||||
}
|
||||
ClassEmitter ce = new ClassEmitter(v);
|
||||
ce.begin_class(Constants.V1_8,
|
||||
Constants.ACC_PUBLIC,
|
||||
getClassName(),
|
||||
superclass != null ? Type.getType(superclass) : Constants.TYPE_OBJECT,
|
||||
null,
|
||||
null);
|
||||
EmitUtils.null_constructor(ce);
|
||||
EmitUtils.add_properties(ce, names, types);
|
||||
ce.end_class();
|
||||
}
|
||||
public void generateClass(ClassVisitor v) throws Exception {
|
||||
int size = props.size();
|
||||
String[] names = (String[])props.keySet().toArray(new String[size]);
|
||||
Type[] types = new Type[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
types[i] = (Type)props.get(names[i]);
|
||||
}
|
||||
ClassEmitter ce = new ClassEmitter(v);
|
||||
ce.begin_class(Constants.V1_8,
|
||||
Constants.ACC_PUBLIC,
|
||||
getClassName(),
|
||||
superclass != null ? Type.getType(superclass) : Constants.TYPE_OBJECT,
|
||||
null,
|
||||
null);
|
||||
EmitUtils.null_constructor(ce);
|
||||
EmitUtils.add_properties(ce, names, types);
|
||||
ce.end_class();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object firstInstance(Class type) {
|
||||
if (classOnly) {
|
||||
return type;
|
||||
} else {
|
||||
return ReflectUtils.newInstance(type);
|
||||
}
|
||||
}
|
||||
protected Object firstInstance(Class type) {
|
||||
if (classOnly) {
|
||||
return type;
|
||||
} else {
|
||||
return ReflectUtils.newInstance(type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object nextInstance(Object instance) {
|
||||
Class protoclass = (instance instanceof Class) ? (Class)instance : instance.getClass();
|
||||
if (classOnly) {
|
||||
return protoclass;
|
||||
} else {
|
||||
return ReflectUtils.newInstance(protoclass);
|
||||
}
|
||||
}
|
||||
protected Object nextInstance(Object instance) {
|
||||
Class protoclass = (instance instanceof Class) ? (Class)instance : instance.getClass();
|
||||
if (classOnly) {
|
||||
return protoclass;
|
||||
} else {
|
||||
return ReflectUtils.newInstance(protoclass);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addProperties(BeanGenerator gen, Map props) {
|
||||
for (Iterator it = props.keySet().iterator(); it.hasNext();) {
|
||||
String name = (String)it.next();
|
||||
gen.addProperty(name, (Class)props.get(name));
|
||||
}
|
||||
}
|
||||
public static void addProperties(BeanGenerator gen, Map props) {
|
||||
for (Iterator it = props.keySet().iterator(); it.hasNext();) {
|
||||
String name = (String)it.next();
|
||||
gen.addProperty(name, (Class)props.get(name));
|
||||
}
|
||||
}
|
||||
|
||||
public static void addProperties(BeanGenerator gen, Class type) {
|
||||
addProperties(gen, ReflectUtils.getBeanProperties(type));
|
||||
}
|
||||
public static void addProperties(BeanGenerator gen, Class type) {
|
||||
addProperties(gen, ReflectUtils.getBeanProperties(type));
|
||||
}
|
||||
|
||||
public static void addProperties(BeanGenerator gen, PropertyDescriptor[] descriptors) {
|
||||
for (PropertyDescriptor descriptor : descriptors) {
|
||||
gen.addProperty(descriptor.getName(), descriptor.getPropertyType());
|
||||
}
|
||||
}
|
||||
public static void addProperties(BeanGenerator gen, PropertyDescriptor[] descriptors) {
|
||||
for (int i = 0; i < descriptors.length; i++) {
|
||||
gen.addProperty(descriptors[i].getName(), descriptors[i].getPropertyType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,310 +41,293 @@ import org.springframework.cglib.core.ReflectUtils;
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class BeanMap implements Map {
|
||||
/**
|
||||
* Limit the properties reflected in the key set of the map
|
||||
* to readable properties.
|
||||
* @see BeanMap.Generator#setRequire
|
||||
*/
|
||||
public static final int REQUIRE_GETTER = 1;
|
||||
/**
|
||||
* Limit the properties reflected in the key set of the map
|
||||
* to readable properties.
|
||||
* @see BeanMap.Generator#setRequire
|
||||
*/
|
||||
public static final int REQUIRE_GETTER = 1;
|
||||
|
||||
/**
|
||||
* Limit the properties reflected in the key set of the map
|
||||
* to writable properties.
|
||||
* @see BeanMap.Generator#setRequire
|
||||
*/
|
||||
public static final int REQUIRE_SETTER = 2;
|
||||
/**
|
||||
* Limit the properties reflected in the key set of the map
|
||||
* to writable properties.
|
||||
* @see BeanMap.Generator#setRequire
|
||||
*/
|
||||
public static final int REQUIRE_SETTER = 2;
|
||||
|
||||
/**
|
||||
* Helper method to create a new <code>BeanMap</code>. For finer
|
||||
* control over the generated instance, use a new instance of
|
||||
* <code>BeanMap.Generator</code> instead of this static method.
|
||||
* @param bean the JavaBean underlying the map
|
||||
* @return a new <code>BeanMap</code> instance
|
||||
*/
|
||||
public static BeanMap create(Object bean) {
|
||||
Generator gen = new Generator();
|
||||
gen.setBean(bean);
|
||||
return gen.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a new <code>BeanMap</code>. For finer
|
||||
* control over the generated instance, use a new instance of
|
||||
* <code>BeanMap.Generator</code> instead of this static method.
|
||||
* @param bean the JavaBean underlying the map
|
||||
* @return a new <code>BeanMap</code> instance
|
||||
*/
|
||||
public static BeanMap create(Object bean) {
|
||||
Generator gen = new Generator();
|
||||
gen.setBean(bean);
|
||||
return gen.create();
|
||||
}
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(BeanMap.class.getName());
|
||||
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(BeanMap.class.getName());
|
||||
private static final BeanMapKey KEY_FACTORY =
|
||||
(BeanMapKey)KeyFactory.create(BeanMapKey.class, KeyFactory.CLASS_BY_NAME);
|
||||
|
||||
private static final BeanMapKey KEY_FACTORY =
|
||||
(BeanMapKey)KeyFactory.create(BeanMapKey.class, KeyFactory.CLASS_BY_NAME);
|
||||
interface BeanMapKey {
|
||||
public Object newInstance(Class type, int require);
|
||||
}
|
||||
|
||||
private Object bean;
|
||||
private Class beanClass;
|
||||
private int require;
|
||||
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
interface BeanMapKey {
|
||||
public Object newInstance(Class type, int require);
|
||||
}
|
||||
|
||||
private Object bean;
|
||||
private Class beanClass;
|
||||
private int require;
|
||||
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean that the generated map should reflect. The bean may be swapped
|
||||
* out for another bean of the same type using {@link #setBean}.
|
||||
* Calling this method overrides any value previously set using {@link #setBeanClass}.
|
||||
* You must call either this method or {@link #setBeanClass} before {@link #create}.
|
||||
* @param bean the initial bean
|
||||
*/
|
||||
public void setBean(Object bean) {
|
||||
this.bean = bean;
|
||||
if (bean != null) {
|
||||
/**
|
||||
* Set the bean that the generated map should reflect. The bean may be swapped
|
||||
* out for another bean of the same type using {@link #setBean}.
|
||||
* Calling this method overrides any value previously set using {@link #setBeanClass}.
|
||||
* You must call either this method or {@link #setBeanClass} before {@link #create}.
|
||||
* @param bean the initial bean
|
||||
*/
|
||||
public void setBean(Object bean) {
|
||||
this.bean = bean;
|
||||
if (bean != null) {
|
||||
beanClass = bean.getClass();
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(beanClass);
|
||||
// SPRING PATCH END
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class of the bean that the generated map should support.
|
||||
* You must call either this method or {@link #setBeanClass} before {@link #create}.
|
||||
* @param beanClass the class of the bean
|
||||
*/
|
||||
public void setBeanClass(Class beanClass) {
|
||||
this.beanClass = beanClass;
|
||||
}
|
||||
/**
|
||||
* Set the class of the bean that the generated map should support.
|
||||
* You must call either this method or {@link #setBeanClass} before {@link #create}.
|
||||
* @param beanClass the class of the bean
|
||||
*/
|
||||
public void setBeanClass(Class beanClass) {
|
||||
this.beanClass = beanClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit the properties reflected by the generated map.
|
||||
* @param require any combination of {@link #REQUIRE_GETTER} and
|
||||
* {@link #REQUIRE_SETTER}; default is zero (any property allowed)
|
||||
*/
|
||||
public void setRequire(int require) {
|
||||
this.require = require;
|
||||
}
|
||||
/**
|
||||
* Limit the properties reflected by the generated map.
|
||||
* @param require any combination of {@link #REQUIRE_GETTER} and
|
||||
* {@link #REQUIRE_SETTER}; default is zero (any property allowed)
|
||||
*/
|
||||
public void setRequire(int require) {
|
||||
this.require = require;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return beanClass.getClassLoader();
|
||||
}
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return beanClass.getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(beanClass);
|
||||
}
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(beanClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the <code>BeanMap</code>. An existing
|
||||
* generated class will be reused if possible.
|
||||
*/
|
||||
public BeanMap create() {
|
||||
if (beanClass == null) {
|
||||
throw new IllegalArgumentException("Class of bean unknown");
|
||||
}
|
||||
setNamePrefix(beanClass.getName());
|
||||
return (BeanMap)super.create(KEY_FACTORY.newInstance(beanClass, require));
|
||||
}
|
||||
/**
|
||||
* Create a new instance of the <code>BeanMap</code>. An existing
|
||||
* generated class will be reused if possible.
|
||||
*/
|
||||
public BeanMap create() {
|
||||
if (beanClass == null)
|
||||
throw new IllegalArgumentException("Class of bean unknown");
|
||||
setNamePrefix(beanClass.getName());
|
||||
return (BeanMap)super.create(KEY_FACTORY.newInstance(beanClass, require));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateClass(ClassVisitor v) throws Exception {
|
||||
new BeanMapEmitter(v, getClassName(), beanClass, require);
|
||||
}
|
||||
public void generateClass(ClassVisitor v) throws Exception {
|
||||
new BeanMapEmitter(v, getClassName(), beanClass, require);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object firstInstance(Class type) {
|
||||
return ((BeanMap)ReflectUtils.newInstance(type)).newInstance(bean);
|
||||
}
|
||||
protected Object firstInstance(Class type) {
|
||||
return ((BeanMap)ReflectUtils.newInstance(type)).newInstance(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object nextInstance(Object instance) {
|
||||
return ((BeanMap)instance).newInstance(bean);
|
||||
}
|
||||
}
|
||||
protected Object nextInstance(Object instance) {
|
||||
return ((BeanMap)instance).newInstance(bean);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new <code>BeanMap</code> instance using the specified bean.
|
||||
* This is faster than using the {@link #create} static method.
|
||||
* @param bean the JavaBean underlying the map
|
||||
* @return a new <code>BeanMap</code> instance
|
||||
*/
|
||||
abstract public BeanMap newInstance(Object bean);
|
||||
/**
|
||||
* Create a new <code>BeanMap</code> instance using the specified bean.
|
||||
* This is faster than using the {@link #create} static method.
|
||||
* @param bean the JavaBean underlying the map
|
||||
* @return a new <code>BeanMap</code> instance
|
||||
*/
|
||||
abstract public BeanMap newInstance(Object bean);
|
||||
|
||||
/**
|
||||
* Get the type of a property.
|
||||
* @param name the name of the JavaBean property
|
||||
* @return the type of the property, or null if the property does not exist
|
||||
*/
|
||||
abstract public Class getPropertyType(String name);
|
||||
/**
|
||||
* Get the type of a property.
|
||||
* @param name the name of the JavaBean property
|
||||
* @return the type of the property, or null if the property does not exist
|
||||
*/
|
||||
abstract public Class getPropertyType(String name);
|
||||
|
||||
protected Object bean;
|
||||
protected Object bean;
|
||||
|
||||
protected BeanMap() {
|
||||
}
|
||||
protected BeanMap() {
|
||||
}
|
||||
|
||||
protected BeanMap(Object bean) {
|
||||
setBean(bean);
|
||||
}
|
||||
protected BeanMap(Object bean) {
|
||||
setBean(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return get(bean, key);
|
||||
}
|
||||
public Object get(Object key) {
|
||||
return get(bean, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object put(Object key, Object value) {
|
||||
return put(bean, key, value);
|
||||
}
|
||||
public Object put(Object key, Object value) {
|
||||
return put(bean, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the property of a bean. This allows a <code>BeanMap</code>
|
||||
* to be used statically for multiple beans--the bean instance tied to the
|
||||
* map is ignored and the bean passed to this method is used instead.
|
||||
* @param bean the bean to query; must be compatible with the type of
|
||||
* this <code>BeanMap</code>
|
||||
* @param key must be a String
|
||||
* @return the current value, or null if there is no matching property
|
||||
*/
|
||||
abstract public Object get(Object bean, Object key);
|
||||
/**
|
||||
* Get the property of a bean. This allows a <code>BeanMap</code>
|
||||
* to be used statically for multiple beans--the bean instance tied to the
|
||||
* map is ignored and the bean passed to this method is used instead.
|
||||
* @param bean the bean to query; must be compatible with the type of
|
||||
* this <code>BeanMap</code>
|
||||
* @param key must be a String
|
||||
* @return the current value, or null if there is no matching property
|
||||
*/
|
||||
abstract public Object get(Object bean, Object key);
|
||||
|
||||
/**
|
||||
* Set the property of a bean. This allows a <code>BeanMap</code>
|
||||
* to be used statically for multiple beans--the bean instance tied to the
|
||||
* map is ignored and the bean passed to this method is used instead.
|
||||
* @param key must be a String
|
||||
* @return the old value, if there was one, or null
|
||||
*/
|
||||
abstract public Object put(Object bean, Object key, Object value);
|
||||
/**
|
||||
* Set the property of a bean. This allows a <code>BeanMap</code>
|
||||
* to be used statically for multiple beans--the bean instance tied to the
|
||||
* map is ignored and the bean passed to this method is used instead.
|
||||
* @param key must be a String
|
||||
* @return the old value, if there was one, or null
|
||||
*/
|
||||
abstract public Object put(Object bean, Object key, Object value);
|
||||
|
||||
/**
|
||||
* Change the underlying bean this map should use.
|
||||
* @param bean the new JavaBean
|
||||
* @see #getBean
|
||||
*/
|
||||
public void setBean(Object bean) {
|
||||
this.bean = bean;
|
||||
}
|
||||
/**
|
||||
* Change the underlying bean this map should use.
|
||||
* @param bean the new JavaBean
|
||||
* @see #getBean
|
||||
*/
|
||||
public void setBean(Object bean) {
|
||||
this.bean = bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean currently in use by this map.
|
||||
* @return the current JavaBean
|
||||
* @see #setBean
|
||||
*/
|
||||
public Object getBean() {
|
||||
return bean;
|
||||
}
|
||||
/**
|
||||
* Return the bean currently in use by this map.
|
||||
* @return the current JavaBean
|
||||
* @see #setBean
|
||||
*/
|
||||
public Object getBean() {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return keySet().contains(key);
|
||||
}
|
||||
public boolean containsKey(Object key) {
|
||||
return keySet().contains(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
Object v = get(it.next());
|
||||
if (((value == null) && (v == null)) || (value != null && value.equals(v))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public boolean containsValue(Object value) {
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
Object v = get(it.next());
|
||||
if (((value == null) && (v == null)) || (value != null && value.equals(v)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return keySet().size();
|
||||
}
|
||||
public int size() {
|
||||
return keySet().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(Object key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public Object remove(Object key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map t) {
|
||||
for (Object key : t.keySet()) {
|
||||
put(key, t.get(key));
|
||||
}
|
||||
}
|
||||
public void putAll(Map t) {
|
||||
for (Iterator it = t.keySet().iterator(); it.hasNext();) {
|
||||
Object key = it.next();
|
||||
put(key, t.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || !(o instanceof Map)) {
|
||||
return false;
|
||||
}
|
||||
Map other = (Map)o;
|
||||
if (size() != other.size()) {
|
||||
return false;
|
||||
}
|
||||
for (Object key : keySet()) {
|
||||
if (!other.containsKey(key)) {
|
||||
return false;
|
||||
}
|
||||
Object v1 = get(key);
|
||||
Object v2 = other.get(key);
|
||||
if (!((v1 == null) ? v2 == null : v1.equals(v2))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || !(o instanceof Map)) {
|
||||
return false;
|
||||
}
|
||||
Map other = (Map)o;
|
||||
if (size() != other.size()) {
|
||||
return false;
|
||||
}
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
Object key = it.next();
|
||||
if (!other.containsKey(key)) {
|
||||
return false;
|
||||
}
|
||||
Object v1 = get(key);
|
||||
Object v2 = other.get(key);
|
||||
if (!((v1 == null) ? v2 == null : v1.equals(v2))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int code = 0;
|
||||
for (Object key : keySet()) {
|
||||
Object value = get(key);
|
||||
code += ((key == null) ? 0 : key.hashCode()) ^
|
||||
((value == null) ? 0 : value.hashCode());
|
||||
}
|
||||
return code;
|
||||
}
|
||||
public int hashCode() {
|
||||
int code = 0;
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
Object key = it.next();
|
||||
Object value = get(key);
|
||||
code += ((key == null) ? 0 : key.hashCode()) ^
|
||||
((value == null) ? 0 : value.hashCode());
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
// TODO: optimize
|
||||
@Override
|
||||
public Set entrySet() {
|
||||
HashMap copy = new HashMap();
|
||||
for (Object key : keySet()) {
|
||||
copy.put(key, get(key));
|
||||
}
|
||||
return Collections.unmodifiableMap(copy).entrySet();
|
||||
}
|
||||
// TODO: optimize
|
||||
public Set entrySet() {
|
||||
HashMap copy = new HashMap();
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
Object key = it.next();
|
||||
copy.put(key, get(key));
|
||||
}
|
||||
return Collections.unmodifiableMap(copy).entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection values() {
|
||||
Set keys = keySet();
|
||||
List values = new ArrayList(keys.size());
|
||||
for (Iterator it = keys.iterator(); it.hasNext();) {
|
||||
values.add(get(it.next()));
|
||||
}
|
||||
return Collections.unmodifiableCollection(values);
|
||||
}
|
||||
public Collection values() {
|
||||
Set keys = keySet();
|
||||
List values = new ArrayList(keys.size());
|
||||
for (Iterator it = keys.iterator(); it.hasNext();) {
|
||||
values.add(get(it.next()));
|
||||
}
|
||||
return Collections.unmodifiableCollection(values);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see java.util.AbstractMap#toString
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('{');
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
Object key = it.next();
|
||||
sb.append(key);
|
||||
sb.append('=');
|
||||
sb.append(get(key));
|
||||
if (it.hasNext()) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
/*
|
||||
* @see java.util.AbstractMap#toString
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append('{');
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
Object key = it.next();
|
||||
sb.append(key);
|
||||
sb.append('=');
|
||||
sb.append(get(key));
|
||||
if (it.hasNext()) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,23 +15,12 @@
|
||||
*/
|
||||
package org.springframework.cglib.beans;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import java.beans.*;
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Label;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.cglib.core.ClassEmitter;
|
||||
import org.springframework.cglib.core.CodeEmitter;
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.cglib.core.EmitUtils;
|
||||
import org.springframework.cglib.core.MethodInfo;
|
||||
import org.springframework.cglib.core.ObjectSwitchCallback;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
import org.springframework.cglib.core.Signature;
|
||||
import org.springframework.cglib.core.TypeUtils;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class BeanMapEmitter extends ClassEmitter {
|
||||
@@ -61,7 +50,7 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
EmitUtils.null_constructor(this);
|
||||
EmitUtils.factory_method(this, NEW_INSTANCE);
|
||||
generateConstructor();
|
||||
|
||||
|
||||
Map getters = makePropertyMap(ReflectUtils.getBeanGetters(type));
|
||||
Map setters = makePropertyMap(ReflectUtils.getBeanSetters(type));
|
||||
Map allProps = new HashMap();
|
||||
@@ -90,8 +79,8 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
|
||||
private Map makePropertyMap(PropertyDescriptor[] props) {
|
||||
Map names = new HashMap();
|
||||
for (PropertyDescriptor prop : props) {
|
||||
names.put(prop.getName(), prop);
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
names.put(props[i].getName(), props[i]);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
@@ -108,7 +97,7 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
|
||||
private void generateGet(Class type, final Map getters) {
|
||||
final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_GET, null);
|
||||
e.load_arg(0);
|
||||
@@ -116,16 +105,14 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
e.load_arg(1);
|
||||
e.checkcast(Constants.TYPE_STRING);
|
||||
EmitUtils.string_switch(e, getNames(getters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
|
||||
@Override
|
||||
public void processCase(Object key, Label end) {
|
||||
public void processCase(Object key, Label end) {
|
||||
PropertyDescriptor pd = (PropertyDescriptor)getters.get(key);
|
||||
MethodInfo method = ReflectUtils.getMethodInfo(pd.getReadMethod());
|
||||
e.invoke(method);
|
||||
e.box(method.getSignature().getReturnType());
|
||||
e.return_value();
|
||||
}
|
||||
@Override
|
||||
public void processDefault() {
|
||||
public void processDefault() {
|
||||
e.aconst_null();
|
||||
e.return_value();
|
||||
}
|
||||
@@ -140,8 +127,7 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
e.load_arg(1);
|
||||
e.checkcast(Constants.TYPE_STRING);
|
||||
EmitUtils.string_switch(e, getNames(setters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
|
||||
@Override
|
||||
public void processCase(Object key, Label end) {
|
||||
public void processCase(Object key, Label end) {
|
||||
PropertyDescriptor pd = (PropertyDescriptor)setters.get(key);
|
||||
if (pd.getReadMethod() == null) {
|
||||
e.aconst_null();
|
||||
@@ -158,8 +144,7 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
e.invoke(write);
|
||||
e.return_value();
|
||||
}
|
||||
@Override
|
||||
public void processDefault() {
|
||||
public void processDefault() {
|
||||
// fall-through
|
||||
}
|
||||
});
|
||||
@@ -167,7 +152,7 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
|
||||
private void generateKeySet(String[] allNames) {
|
||||
// static initializer
|
||||
declare_field(Constants.ACC_STATIC | Constants.ACC_PRIVATE, "keys", FIXED_KEY_SET, null);
|
||||
@@ -193,14 +178,12 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_PROPERTY_TYPE, null);
|
||||
e.load_arg(0);
|
||||
EmitUtils.string_switch(e, allNames, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
|
||||
@Override
|
||||
public void processCase(Object key, Label end) {
|
||||
public void processCase(Object key, Label end) {
|
||||
PropertyDescriptor pd = (PropertyDescriptor)allProps.get(key);
|
||||
EmitUtils.load_class(e, Type.getType(pd.getPropertyType()));
|
||||
e.return_value();
|
||||
}
|
||||
@Override
|
||||
public void processDefault() {
|
||||
public void processDefault() {
|
||||
e.aconst_null();
|
||||
e.return_value();
|
||||
}
|
||||
|
||||
@@ -16,11 +16,8 @@
|
||||
package org.springframework.cglib.beans;
|
||||
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.cglib.core.AbstractClassGenerator;
|
||||
import org.springframework.cglib.core.KeyFactory;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
|
||||
/**
|
||||
* @author Juozas Baliuka
|
||||
@@ -28,123 +25,118 @@ import org.springframework.cglib.core.ReflectUtils;
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class BulkBean
|
||||
{
|
||||
private static final BulkBeanKey KEY_FACTORY =
|
||||
(BulkBeanKey)KeyFactory.create(BulkBeanKey.class);
|
||||
private static final BulkBeanKey KEY_FACTORY =
|
||||
(BulkBeanKey)KeyFactory.create(BulkBeanKey.class);
|
||||
|
||||
interface BulkBeanKey {
|
||||
public Object newInstance(String target, String[] getters, String[] setters, String[] types);
|
||||
}
|
||||
|
||||
protected Class target;
|
||||
protected String[] getters, setters;
|
||||
protected Class[] types;
|
||||
|
||||
protected BulkBean() { }
|
||||
|
||||
abstract public void getPropertyValues(Object bean, Object[] values);
|
||||
abstract public void setPropertyValues(Object bean, Object[] values);
|
||||
|
||||
interface BulkBeanKey {
|
||||
public Object newInstance(String target, String[] getters, String[] setters, String[] types);
|
||||
}
|
||||
public Object[] getPropertyValues(Object bean) {
|
||||
Object[] values = new Object[getters.length];
|
||||
getPropertyValues(bean, values);
|
||||
return values;
|
||||
}
|
||||
|
||||
public Class[] getPropertyTypes() {
|
||||
return types.clone();
|
||||
}
|
||||
|
||||
public String[] getGetters() {
|
||||
return getters.clone();
|
||||
}
|
||||
|
||||
public String[] getSetters() {
|
||||
return setters.clone();
|
||||
}
|
||||
|
||||
protected Class target;
|
||||
protected String[] getters, setters;
|
||||
protected Class[] types;
|
||||
public static BulkBean create(Class target, String[] getters, String[] setters, Class[] types) {
|
||||
Generator gen = new Generator();
|
||||
gen.setTarget(target);
|
||||
gen.setGetters(getters);
|
||||
gen.setSetters(setters);
|
||||
gen.setTypes(types);
|
||||
return gen.create();
|
||||
}
|
||||
|
||||
protected BulkBean() { }
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(BulkBean.class.getName());
|
||||
private Class target;
|
||||
private String[] getters;
|
||||
private String[] setters;
|
||||
private Class[] types;
|
||||
|
||||
abstract public void getPropertyValues(Object bean, Object[] values);
|
||||
abstract public void setPropertyValues(Object bean, Object[] values);
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
public Object[] getPropertyValues(Object bean) {
|
||||
Object[] values = new Object[getters.length];
|
||||
getPropertyValues(bean, values);
|
||||
return values;
|
||||
}
|
||||
|
||||
public Class[] getPropertyTypes() {
|
||||
return types.clone();
|
||||
}
|
||||
|
||||
public String[] getGetters() {
|
||||
return getters.clone();
|
||||
}
|
||||
|
||||
public String[] getSetters() {
|
||||
return setters.clone();
|
||||
}
|
||||
|
||||
public static BulkBean create(Class target, String[] getters, String[] setters, Class[] types) {
|
||||
Generator gen = new Generator();
|
||||
gen.setTarget(target);
|
||||
gen.setGetters(getters);
|
||||
gen.setSetters(setters);
|
||||
gen.setTypes(types);
|
||||
return gen.create();
|
||||
}
|
||||
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(BulkBean.class.getName());
|
||||
private Class target;
|
||||
private String[] getters;
|
||||
private String[] setters;
|
||||
private Class[] types;
|
||||
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
public void setTarget(Class target) {
|
||||
this.target = target;
|
||||
public void setTarget(Class target) {
|
||||
this.target = target;
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(target);
|
||||
// SPRING PATCH END
|
||||
}
|
||||
}
|
||||
|
||||
public void setGetters(String[] getters) {
|
||||
this.getters = getters;
|
||||
}
|
||||
public void setGetters(String[] getters) {
|
||||
this.getters = getters;
|
||||
}
|
||||
|
||||
public void setSetters(String[] setters) {
|
||||
this.setters = setters;
|
||||
}
|
||||
public void setSetters(String[] setters) {
|
||||
this.setters = setters;
|
||||
}
|
||||
|
||||
public void setTypes(Class[] types) {
|
||||
this.types = types;
|
||||
}
|
||||
public void setTypes(Class[] types) {
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return target.getClassLoader();
|
||||
}
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return target.getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(target);
|
||||
}
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(target);
|
||||
}
|
||||
|
||||
public BulkBean create() {
|
||||
setNamePrefix(target.getName());
|
||||
String targetClassName = target.getName();
|
||||
String[] typeClassNames = ReflectUtils.getNames(types);
|
||||
Object key = KEY_FACTORY.newInstance(targetClassName, getters, setters, typeClassNames);
|
||||
return (BulkBean)super.create(key);
|
||||
}
|
||||
public BulkBean create() {
|
||||
setNamePrefix(target.getName());
|
||||
String targetClassName = target.getName();
|
||||
String[] typeClassNames = ReflectUtils.getNames(types);
|
||||
Object key = KEY_FACTORY.newInstance(targetClassName, getters, setters, typeClassNames);
|
||||
return (BulkBean)super.create(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateClass(ClassVisitor v) throws Exception {
|
||||
new BulkBeanEmitter(v, getClassName(), target, getters, setters, types);
|
||||
}
|
||||
public void generateClass(ClassVisitor v) throws Exception {
|
||||
new BulkBeanEmitter(v, getClassName(), target, getters, setters, types);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object firstInstance(Class type) {
|
||||
BulkBean instance = (BulkBean)ReflectUtils.newInstance(type);
|
||||
instance.target = target;
|
||||
protected Object firstInstance(Class type) {
|
||||
BulkBean instance = (BulkBean)ReflectUtils.newInstance(type);
|
||||
instance.target = target;
|
||||
|
||||
int length = getters.length;
|
||||
instance.getters = new String[length];
|
||||
System.arraycopy(getters, 0, instance.getters, 0, length);
|
||||
|
||||
instance.setters = new String[length];
|
||||
System.arraycopy(setters, 0, instance.setters, 0, length);
|
||||
|
||||
instance.types = new Class[types.length];
|
||||
System.arraycopy(types, 0, instance.types, 0, types.length);
|
||||
|
||||
int length = getters.length;
|
||||
instance.getters = new String[length];
|
||||
System.arraycopy(getters, 0, instance.getters, 0, length);
|
||||
return instance;
|
||||
}
|
||||
|
||||
instance.setters = new String[length];
|
||||
System.arraycopy(setters, 0, instance.setters, 0, length);
|
||||
|
||||
instance.types = new Class[types.length];
|
||||
System.arraycopy(types, 0, instance.types, 0, types.length);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object nextInstance(Object instance) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
protected Object nextInstance(Object instance) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,19 +17,9 @@ package org.springframework.cglib.beans;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.cglib.core.Block;
|
||||
import org.springframework.cglib.core.ClassEmitter;
|
||||
import org.springframework.cglib.core.CodeEmitter;
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.cglib.core.EmitUtils;
|
||||
import org.springframework.cglib.core.Local;
|
||||
import org.springframework.cglib.core.MethodInfo;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
import org.springframework.cglib.core.Signature;
|
||||
import org.springframework.cglib.core.TypeUtils;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class BulkBeanEmitter extends ClassEmitter {
|
||||
@@ -43,7 +33,7 @@ class BulkBeanEmitter extends ClassEmitter {
|
||||
TypeUtils.parseType("org.springframework.cglib.beans.BulkBean");
|
||||
private static final Type BULK_BEAN_EXCEPTION =
|
||||
TypeUtils.parseType("org.springframework.cglib.beans.BulkBeanException");
|
||||
|
||||
|
||||
public BulkBeanEmitter(ClassVisitor v,
|
||||
String className,
|
||||
Class target,
|
||||
@@ -126,7 +116,7 @@ class BulkBeanEmitter extends ClassEmitter {
|
||||
}
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
|
||||
private static void validate(Class target,
|
||||
String[] getters,
|
||||
String[] setters,
|
||||
|
||||
@@ -20,7 +20,7 @@ public class BulkBeanException extends RuntimeException
|
||||
{
|
||||
private int index;
|
||||
private Throwable cause;
|
||||
|
||||
|
||||
public BulkBeanException(String message, int index) {
|
||||
super(message);
|
||||
this.index = index;
|
||||
@@ -35,9 +35,8 @@ public class BulkBeanException extends RuntimeException
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getCause() {
|
||||
|
||||
public Throwable getCause() {
|
||||
return cause;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,7 @@
|
||||
*/
|
||||
package org.springframework.cglib.beans;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public /* need it for class loading */ class FixedKeySet extends AbstractSet {
|
||||
@@ -32,13 +27,11 @@ public /* need it for class loading */ class FixedKeySet extends AbstractSet {
|
||||
set = Collections.unmodifiableSet(new HashSet(Arrays.asList(keys)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator iterator() {
|
||||
public Iterator iterator() {
|
||||
return set.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,129 +18,115 @@ package org.springframework.cglib.beans;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.cglib.core.AbstractClassGenerator;
|
||||
import org.springframework.cglib.core.ClassEmitter;
|
||||
import org.springframework.cglib.core.CodeEmitter;
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.cglib.core.EmitUtils;
|
||||
import org.springframework.cglib.core.MethodInfo;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
import org.springframework.cglib.core.Signature;
|
||||
import org.springframework.cglib.core.TypeUtils;
|
||||
/**
|
||||
* @author Chris Nokleberg
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class ImmutableBean
|
||||
{
|
||||
private static final Type ILLEGAL_STATE_EXCEPTION =
|
||||
TypeUtils.parseType("IllegalStateException");
|
||||
private static final Signature CSTRUCT_OBJECT =
|
||||
TypeUtils.parseConstructor("Object");
|
||||
private static final Class[] OBJECT_CLASSES = { Object.class };
|
||||
private static final String FIELD_NAME = "CGLIB$RWBean";
|
||||
private static final Type ILLEGAL_STATE_EXCEPTION =
|
||||
TypeUtils.parseType("IllegalStateException");
|
||||
private static final Signature CSTRUCT_OBJECT =
|
||||
TypeUtils.parseConstructor("Object");
|
||||
private static final Class[] OBJECT_CLASSES = { Object.class };
|
||||
private static final String FIELD_NAME = "CGLIB$RWBean";
|
||||
|
||||
private ImmutableBean() {
|
||||
}
|
||||
private ImmutableBean() {
|
||||
}
|
||||
|
||||
public static Object create(Object bean) {
|
||||
Generator gen = new Generator();
|
||||
gen.setBean(bean);
|
||||
return gen.create();
|
||||
}
|
||||
public static Object create(Object bean) {
|
||||
Generator gen = new Generator();
|
||||
gen.setBean(bean);
|
||||
return gen.create();
|
||||
}
|
||||
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(ImmutableBean.class.getName());
|
||||
private Object bean;
|
||||
private Class target;
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(ImmutableBean.class.getName());
|
||||
private Object bean;
|
||||
private Class target;
|
||||
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
public void setBean(Object bean) {
|
||||
this.bean = bean;
|
||||
target = bean.getClass();
|
||||
public void setBean(Object bean) {
|
||||
this.bean = bean;
|
||||
target = bean.getClass();
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(target);
|
||||
// SPRING PATCH END
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return target.getClassLoader();
|
||||
}
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return target.getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(target);
|
||||
}
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(target);
|
||||
}
|
||||
|
||||
public Object create() {
|
||||
String name = target.getName();
|
||||
setNamePrefix(name);
|
||||
return super.create(name);
|
||||
}
|
||||
public Object create() {
|
||||
String name = target.getName();
|
||||
setNamePrefix(name);
|
||||
return super.create(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateClass(ClassVisitor v) {
|
||||
Type targetType = Type.getType(target);
|
||||
ClassEmitter ce = new ClassEmitter(v);
|
||||
ce.begin_class(Constants.V1_8,
|
||||
Constants.ACC_PUBLIC,
|
||||
getClassName(),
|
||||
targetType,
|
||||
null,
|
||||
Constants.SOURCE_FILE);
|
||||
public void generateClass(ClassVisitor v) {
|
||||
Type targetType = Type.getType(target);
|
||||
ClassEmitter ce = new ClassEmitter(v);
|
||||
ce.begin_class(Constants.V1_8,
|
||||
Constants.ACC_PUBLIC,
|
||||
getClassName(),
|
||||
targetType,
|
||||
null,
|
||||
Constants.SOURCE_FILE);
|
||||
|
||||
ce.declare_field(Constants.ACC_FINAL | Constants.ACC_PRIVATE, FIELD_NAME, targetType, null);
|
||||
ce.declare_field(Constants.ACC_FINAL | Constants.ACC_PRIVATE, FIELD_NAME, targetType, null);
|
||||
|
||||
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT, null);
|
||||
e.load_this();
|
||||
e.super_invoke_constructor();
|
||||
e.load_this();
|
||||
e.load_arg(0);
|
||||
e.checkcast(targetType);
|
||||
e.putfield(FIELD_NAME);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT, null);
|
||||
e.load_this();
|
||||
e.super_invoke_constructor();
|
||||
e.load_this();
|
||||
e.load_arg(0);
|
||||
e.checkcast(targetType);
|
||||
e.putfield(FIELD_NAME);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
PropertyDescriptor[] descriptors = ReflectUtils.getBeanProperties(target);
|
||||
Method[] getters = ReflectUtils.getPropertyMethods(descriptors, true, false);
|
||||
Method[] setters = ReflectUtils.getPropertyMethods(descriptors, false, true);
|
||||
PropertyDescriptor[] descriptors = ReflectUtils.getBeanProperties(target);
|
||||
Method[] getters = ReflectUtils.getPropertyMethods(descriptors, true, false);
|
||||
Method[] setters = ReflectUtils.getPropertyMethods(descriptors, false, true);
|
||||
|
||||
for (Method getter2 : getters) {
|
||||
MethodInfo getter = ReflectUtils.getMethodInfo(getter2);
|
||||
e = EmitUtils.begin_method(ce, getter, Constants.ACC_PUBLIC);
|
||||
e.load_this();
|
||||
e.getfield(FIELD_NAME);
|
||||
e.invoke(getter);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
for (int i = 0; i < getters.length; i++) {
|
||||
MethodInfo getter = ReflectUtils.getMethodInfo(getters[i]);
|
||||
e = EmitUtils.begin_method(ce, getter, Constants.ACC_PUBLIC);
|
||||
e.load_this();
|
||||
e.getfield(FIELD_NAME);
|
||||
e.invoke(getter);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
for (Method setter2 : setters) {
|
||||
MethodInfo setter = ReflectUtils.getMethodInfo(setter2);
|
||||
e = EmitUtils.begin_method(ce, setter, Constants.ACC_PUBLIC);
|
||||
e.throw_exception(ILLEGAL_STATE_EXCEPTION, "Bean is immutable");
|
||||
e.end_method();
|
||||
}
|
||||
for (int i = 0; i < setters.length; i++) {
|
||||
MethodInfo setter = ReflectUtils.getMethodInfo(setters[i]);
|
||||
e = EmitUtils.begin_method(ce, setter, Constants.ACC_PUBLIC);
|
||||
e.throw_exception(ILLEGAL_STATE_EXCEPTION, "Bean is immutable");
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
ce.end_class();
|
||||
}
|
||||
ce.end_class();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object firstInstance(Class type) {
|
||||
return ReflectUtils.newInstance(type, OBJECT_CLASSES, new Object[]{ bean });
|
||||
}
|
||||
protected Object firstInstance(Class type) {
|
||||
return ReflectUtils.newInstance(type, OBJECT_CLASSES, new Object[]{ bean });
|
||||
}
|
||||
|
||||
// TODO: optimize
|
||||
@Override
|
||||
protected Object nextInstance(Object instance) {
|
||||
return firstInstance(instance.getClass());
|
||||
}
|
||||
}
|
||||
// TODO: optimize
|
||||
protected Object nextInstance(Object instance) {
|
||||
return firstInstance(instance.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ public class ResolvableType implements Serializable {
|
||||
|
||||
|
||||
/**
|
||||
* Private constructor used to create a new {@code ResolvableType} for cache key purposes,
|
||||
* Private constructor used to create a new {@link ResolvableType} for cache key purposes,
|
||||
* with no upfront resolution.
|
||||
*/
|
||||
private ResolvableType(
|
||||
@@ -153,7 +153,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor used to create a new {@code ResolvableType} for cache value purposes,
|
||||
* Private constructor used to create a new {@link ResolvableType} for cache value purposes,
|
||||
* with upfront resolution and a pre-calculated hash.
|
||||
* @since 4.2
|
||||
*/
|
||||
@@ -169,7 +169,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor used to create a new {@code ResolvableType} for uncached purposes,
|
||||
* Private constructor used to create a new {@link ResolvableType} for uncached purposes,
|
||||
* with upfront resolution but lazily calculated hash.
|
||||
*/
|
||||
private ResolvableType(Type type, @Nullable TypeProvider typeProvider,
|
||||
@@ -184,7 +184,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor used to create a new {@code ResolvableType} on a {@link Class} basis.
|
||||
* Private constructor used to create a new {@link ResolvableType} on a {@link Class} basis.
|
||||
* <p>Avoids all {@code instanceof} checks in order to create a straight {@link Class} wrapper.
|
||||
* @since 4.2
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ public class ResolvableType implements Serializable {
|
||||
|
||||
/**
|
||||
* Return the underlying source of the resolvable type. Will return a {@link Field},
|
||||
* {@link MethodParameter} or {@link Type} depending on how the {@code ResolvableType}
|
||||
* {@link MethodParameter} or {@link Type} depending on how the {@link ResolvableType}
|
||||
* was constructed. This method is primarily to provide access to additional type
|
||||
* information or meta-data that alternative JVM languages may provide.
|
||||
*/
|
||||
@@ -341,14 +341,13 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
}
|
||||
if (ourResolved == null) {
|
||||
ourResolved = toClass();
|
||||
ourResolved = resolve(Object.class);
|
||||
}
|
||||
Class<?> otherResolved = other.toClass();
|
||||
|
||||
// We need an exact type match for generics
|
||||
// List<CharSequence> is not assignable from List<String>
|
||||
if (exactMatch ? !ourResolved.equals(otherResolved) :
|
||||
!ClassUtils.isAssignable(ourResolved, otherResolved)) {
|
||||
if (exactMatch ? !ourResolved.equals(otherResolved) : !ClassUtils.isAssignable(ourResolved, otherResolved)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -359,15 +358,13 @@ public class ResolvableType implements Serializable {
|
||||
if (ourGenerics.length != typeGenerics.length) {
|
||||
return false;
|
||||
}
|
||||
if (ourGenerics.length > 0) {
|
||||
if (matchedBefore == null) {
|
||||
matchedBefore = new IdentityHashMap<>(1);
|
||||
}
|
||||
matchedBefore.put(this.type, other.type);
|
||||
for (int i = 0; i < ourGenerics.length; i++) {
|
||||
if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], matchedBefore)) {
|
||||
return false;
|
||||
}
|
||||
if (matchedBefore == null) {
|
||||
matchedBefore = new IdentityHashMap<>(1);
|
||||
}
|
||||
matchedBefore.put(this.type, other.type);
|
||||
for (int i = 0; i < ourGenerics.length; i++) {
|
||||
if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], matchedBefore)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -432,12 +429,12 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this type as a {@code ResolvableType} of the specified class. Searches
|
||||
* Return this type as a {@link ResolvableType} of the specified class. Searches
|
||||
* {@link #getSuperType() supertype} and {@link #getInterfaces() interface}
|
||||
* hierarchies to find a match, returning {@link #NONE} if this type does not
|
||||
* implement or extend the specified class.
|
||||
* @param type the required type (typically narrowed)
|
||||
* @return a {@code ResolvableType} representing this object as the specified
|
||||
* @return a {@link ResolvableType} representing this object as the specified
|
||||
* type, or {@link #NONE} if not resolvable as that type
|
||||
* @see #asCollection()
|
||||
* @see #asMap()
|
||||
@@ -462,9 +459,9 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} representing the direct supertype of this type.
|
||||
* Return a {@link ResolvableType} representing the direct supertype of this type.
|
||||
* <p>If no supertype is available this method returns {@link #NONE}.
|
||||
* <p>Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}.
|
||||
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
|
||||
* @see #getInterfaces()
|
||||
*/
|
||||
public ResolvableType getSuperType() {
|
||||
@@ -491,10 +488,10 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} array representing the direct interfaces
|
||||
* Return a {@link ResolvableType} array representing the direct interfaces
|
||||
* implemented by this type. If this type does not implement any interfaces an
|
||||
* empty array is returned.
|
||||
* <p>Note: The resulting {@code ResolvableType} instances may not be {@link Serializable}.
|
||||
* <p>Note: The resulting {@link ResolvableType} instances may not be {@link Serializable}.
|
||||
* @see #getSuperType()
|
||||
*/
|
||||
public ResolvableType[] getInterfaces() {
|
||||
@@ -624,17 +621,17 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified nesting level.
|
||||
* Return a {@link ResolvableType} for the specified nesting level.
|
||||
* <p>See {@link #getNested(int, Map)} for details.
|
||||
* @param nestingLevel the nesting level
|
||||
* @return the {@code ResolvableType} type, or {@code #NONE}
|
||||
* @return the {@link ResolvableType} type, or {@code #NONE}
|
||||
*/
|
||||
public ResolvableType getNested(int nestingLevel) {
|
||||
return getNested(nestingLevel, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified nesting level.
|
||||
* Return a {@link ResolvableType} for the specified nesting level.
|
||||
* <p>The nesting level refers to the specific generic parameter that should be returned.
|
||||
* A nesting level of 1 indicates this type; 2 indicates the first nested generic;
|
||||
* 3 the second; and so on. For example, given {@code List<Set<Integer>>} level 1 refers
|
||||
@@ -651,7 +648,7 @@ public class ResolvableType implements Serializable {
|
||||
* current type, 2 for the first nested generic, 3 for the second and so on
|
||||
* @param typeIndexesPerLevel a map containing the generic index for a given
|
||||
* nesting level (may be {@code null})
|
||||
* @return a {@code ResolvableType} for the nested level, or {@link #NONE}
|
||||
* @return a {@link ResolvableType} for the nested level, or {@link #NONE}
|
||||
*/
|
||||
public ResolvableType getNested(int nestingLevel, @Nullable Map<Integer, Integer> typeIndexesPerLevel) {
|
||||
ResolvableType result = this;
|
||||
@@ -673,7 +670,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} representing the generic parameter for the
|
||||
* Return a {@link ResolvableType} representing the generic parameter for the
|
||||
* given indexes. Indexes are zero based; for example given the type
|
||||
* {@code Map<Integer, List<String>>}, {@code getGeneric(0)} will access the
|
||||
* {@code Integer}. Nested generics can be accessed by specifying multiple indexes;
|
||||
@@ -683,7 +680,7 @@ public class ResolvableType implements Serializable {
|
||||
* <p>If no generic is available at the specified indexes {@link #NONE} is returned.
|
||||
* @param indexes the indexes that refer to the generic parameter
|
||||
* (may be omitted to return the first generic)
|
||||
* @return a {@code ResolvableType} for the specified generic, or {@link #NONE}
|
||||
* @return a {@link ResolvableType} for the specified generic, or {@link #NONE}
|
||||
* @see #hasGenerics()
|
||||
* @see #getGenerics()
|
||||
* @see #resolveGeneric(int...)
|
||||
@@ -706,12 +703,12 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of {@code ResolvableType ResolvableTypes} representing the generic parameters of
|
||||
* Return an array of {@link ResolvableType ResolvableTypes} representing the generic parameters of
|
||||
* this type. If no generics are available an empty array is returned. If you need to
|
||||
* access a specific generic consider using the {@link #getGeneric(int...)} method as
|
||||
* it allows access to nested generics and protects against
|
||||
* {@code IndexOutOfBoundsExceptions}.
|
||||
* @return an array of {@code ResolvableType ResolvableTypes} representing the generic parameters
|
||||
* @return an array of {@link ResolvableType ResolvableTypes} representing the generic parameters
|
||||
* (never {@code null})
|
||||
* @see #hasGenerics()
|
||||
* @see #getGeneric(int...)
|
||||
@@ -783,7 +780,7 @@ public class ResolvableType implements Serializable {
|
||||
|
||||
/**
|
||||
* Convenience method that will {@link #getGeneric(int...) get} and
|
||||
* {@link #resolve() resolve} a specific generic parameter.
|
||||
* {@link #resolve() resolve} a specific generic parameters.
|
||||
* @param indexes the indexes that refer to the generic parameter
|
||||
* (may be omitted to return the first generic)
|
||||
* @return a resolved {@link Class} or {@code null}
|
||||
@@ -845,7 +842,7 @@ public class ResolvableType implements Serializable {
|
||||
|
||||
/**
|
||||
* Resolve this type by a single level, returning the resolved value or {@link #NONE}.
|
||||
* <p>Note: The returned {@code ResolvableType} should only be used as an intermediary
|
||||
* <p>Note: The returned {@link ResolvableType} should only be used as an intermediary
|
||||
* as it cannot be serialized.
|
||||
*/
|
||||
ResolvableType resolveType() {
|
||||
@@ -967,7 +964,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts this {@code ResolvableType} to a {@link VariableResolver}.
|
||||
* Adapts this {@link ResolvableType} to a {@link VariableResolver}.
|
||||
*/
|
||||
@Nullable
|
||||
VariableResolver asVariableResolver() {
|
||||
@@ -1014,12 +1011,12 @@ public class ResolvableType implements Serializable {
|
||||
// Factory methods
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Class},
|
||||
* Return a {@link ResolvableType} for the specified {@link Class},
|
||||
* using the full generic type information for assignability checks.
|
||||
* <p>For example: {@code ResolvableType.forClass(MyArrayList.class)}.
|
||||
* @param clazz the class to introspect ({@code null} is semantically
|
||||
* equivalent to {@code Object.class} for typical use cases here)
|
||||
* @return a {@code ResolvableType} for the specified class
|
||||
* @return a {@link ResolvableType} for the specified class
|
||||
* @see #forClass(Class, Class)
|
||||
* @see #forClassWithGenerics(Class, Class...)
|
||||
*/
|
||||
@@ -1028,13 +1025,13 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Class},
|
||||
* Return a {@link ResolvableType} for the specified {@link Class},
|
||||
* doing assignability checks against the raw class only (analogous to
|
||||
* {@link Class#isAssignableFrom}, which this serves as a wrapper for).
|
||||
* <p>For example: {@code ResolvableType.forRawClass(List.class)}.
|
||||
* @param clazz the class to introspect ({@code null} is semantically
|
||||
* equivalent to {@code Object.class} for typical use cases here)
|
||||
* @return a {@code ResolvableType} for the specified class
|
||||
* @return a {@link ResolvableType} for the specified class
|
||||
* @since 4.2
|
||||
* @see #forClass(Class)
|
||||
* @see #getRawClass()
|
||||
@@ -1058,12 +1055,12 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified base type
|
||||
* Return a {@link ResolvableType} for the specified base type
|
||||
* (interface or base class) with a given implementation class.
|
||||
* <p>For example: {@code ResolvableType.forClass(List.class, MyArrayList.class)}.
|
||||
* @param baseType the base type (must not be {@code null})
|
||||
* @param implementationClass the implementation class
|
||||
* @return a {@code ResolvableType} for the specified base type backed by the
|
||||
* @return a {@link ResolvableType} for the specified base type backed by the
|
||||
* given implementation class
|
||||
* @see #forClass(Class)
|
||||
* @see #forClassWithGenerics(Class, Class...)
|
||||
@@ -1075,10 +1072,10 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Class} with pre-declared generics.
|
||||
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics.
|
||||
* @param clazz the class (or interface) to introspect
|
||||
* @param generics the generics of the class
|
||||
* @return a {@code ResolvableType} for the specific class and generics
|
||||
* @return a {@link ResolvableType} for the specific class and generics
|
||||
* @see #forClassWithGenerics(Class, ResolvableType...)
|
||||
*/
|
||||
public static ResolvableType forClassWithGenerics(Class<?> clazz, Class<?>... generics) {
|
||||
@@ -1092,10 +1089,10 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Class} with pre-declared generics.
|
||||
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics.
|
||||
* @param clazz the class (or interface) to introspect
|
||||
* @param generics the generics of the class
|
||||
* @return a {@code ResolvableType} for the specific class and generics
|
||||
* @return a {@link ResolvableType} for the specific class and generics
|
||||
* @see #forClassWithGenerics(Class, Class...)
|
||||
*/
|
||||
public static ResolvableType forClassWithGenerics(Class<?> clazz, ResolvableType... generics) {
|
||||
@@ -1116,12 +1113,12 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified instance. The instance does not
|
||||
* Return a {@link ResolvableType} for the specified instance. The instance does not
|
||||
* convey generic information but if it implements {@link ResolvableTypeProvider} a
|
||||
* more precise {@code ResolvableType} can be used than the simple one based on
|
||||
* more precise {@link ResolvableType} can be used than the simple one based on
|
||||
* the {@link #forClass(Class) Class instance}.
|
||||
* @param instance the instance (possibly {@code null})
|
||||
* @return a {@code ResolvableType} for the specified instance,
|
||||
* @return a {@link ResolvableType} for the specified instance,
|
||||
* or {@code NONE} for {@code null}
|
||||
* @since 4.2
|
||||
* @see ResolvableTypeProvider
|
||||
@@ -1137,9 +1134,9 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Field}.
|
||||
* Return a {@link ResolvableType} for the specified {@link Field}.
|
||||
* @param field the source field
|
||||
* @return a {@code ResolvableType} for the specified field
|
||||
* @return a {@link ResolvableType} for the specified field
|
||||
* @see #forField(Field, Class)
|
||||
*/
|
||||
public static ResolvableType forField(Field field) {
|
||||
@@ -1148,13 +1145,13 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Field} with a given
|
||||
* Return a {@link ResolvableType} for the specified {@link Field} with a given
|
||||
* implementation.
|
||||
* <p>Use this variant when the class that declares the field includes generic
|
||||
* parameter variables that are satisfied by the implementation class.
|
||||
* @param field the source field
|
||||
* @param implementationClass the implementation class
|
||||
* @return a {@code ResolvableType} for the specified field
|
||||
* @return a {@link ResolvableType} for the specified field
|
||||
* @see #forField(Field)
|
||||
*/
|
||||
public static ResolvableType forField(Field field, Class<?> implementationClass) {
|
||||
@@ -1164,13 +1161,13 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Field} with a given
|
||||
* Return a {@link ResolvableType} for the specified {@link Field} with a given
|
||||
* implementation.
|
||||
* <p>Use this variant when the class that declares the field includes generic
|
||||
* parameter variables that are satisfied by the implementation type.
|
||||
* @param field the source field
|
||||
* @param implementationType the implementation type
|
||||
* @return a {@code ResolvableType} for the specified field
|
||||
* @return a {@link ResolvableType} for the specified field
|
||||
* @see #forField(Field)
|
||||
*/
|
||||
public static ResolvableType forField(Field field, @Nullable ResolvableType implementationType) {
|
||||
@@ -1181,7 +1178,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Field} with the
|
||||
* Return a {@link ResolvableType} for the specified {@link Field} with the
|
||||
* given nesting level.
|
||||
* @param field the source field
|
||||
* @param nestingLevel the nesting level (1 for the outer level; 2 for a nested
|
||||
@@ -1194,7 +1191,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Field} with a given
|
||||
* Return a {@link ResolvableType} for the specified {@link Field} with a given
|
||||
* implementation and the given nesting level.
|
||||
* <p>Use this variant when the class that declares the field includes generic
|
||||
* parameter variables that are satisfied by the implementation class.
|
||||
@@ -1202,7 +1199,7 @@ public class ResolvableType implements Serializable {
|
||||
* @param nestingLevel the nesting level (1 for the outer level; 2 for a nested
|
||||
* generic type; etc)
|
||||
* @param implementationClass the implementation class
|
||||
* @return a {@code ResolvableType} for the specified field
|
||||
* @return a {@link ResolvableType} for the specified field
|
||||
* @see #forField(Field)
|
||||
*/
|
||||
public static ResolvableType forField(Field field, int nestingLevel, @Nullable Class<?> implementationClass) {
|
||||
@@ -1212,10 +1209,10 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Constructor} parameter.
|
||||
* Return a {@link ResolvableType} for the specified {@link Constructor} parameter.
|
||||
* @param constructor the source constructor (must not be {@code null})
|
||||
* @param parameterIndex the parameter index
|
||||
* @return a {@code ResolvableType} for the specified constructor parameter
|
||||
* @return a {@link ResolvableType} for the specified constructor parameter
|
||||
* @see #forConstructorParameter(Constructor, int, Class)
|
||||
*/
|
||||
public static ResolvableType forConstructorParameter(Constructor<?> constructor, int parameterIndex) {
|
||||
@@ -1224,14 +1221,14 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Constructor} parameter
|
||||
* Return a {@link ResolvableType} for the specified {@link Constructor} parameter
|
||||
* with a given implementation. Use this variant when the class that declares the
|
||||
* constructor includes generic parameter variables that are satisfied by the
|
||||
* implementation class.
|
||||
* @param constructor the source constructor (must not be {@code null})
|
||||
* @param parameterIndex the parameter index
|
||||
* @param implementationClass the implementation class
|
||||
* @return a {@code ResolvableType} for the specified constructor parameter
|
||||
* @return a {@link ResolvableType} for the specified constructor parameter
|
||||
* @see #forConstructorParameter(Constructor, int)
|
||||
*/
|
||||
public static ResolvableType forConstructorParameter(Constructor<?> constructor, int parameterIndex,
|
||||
@@ -1243,9 +1240,9 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Method} return type.
|
||||
* Return a {@link ResolvableType} for the specified {@link Method} return type.
|
||||
* @param method the source for the method return type
|
||||
* @return a {@code ResolvableType} for the specified method return
|
||||
* @return a {@link ResolvableType} for the specified method return
|
||||
* @see #forMethodReturnType(Method, Class)
|
||||
*/
|
||||
public static ResolvableType forMethodReturnType(Method method) {
|
||||
@@ -1254,12 +1251,12 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Method} return type.
|
||||
* Return a {@link ResolvableType} for the specified {@link Method} return type.
|
||||
* <p>Use this variant when the class that declares the method includes generic
|
||||
* parameter variables that are satisfied by the implementation class.
|
||||
* @param method the source for the method return type
|
||||
* @param implementationClass the implementation class
|
||||
* @return a {@code ResolvableType} for the specified method return
|
||||
* @return a {@link ResolvableType} for the specified method return
|
||||
* @see #forMethodReturnType(Method)
|
||||
*/
|
||||
public static ResolvableType forMethodReturnType(Method method, Class<?> implementationClass) {
|
||||
@@ -1269,10 +1266,10 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Method} parameter.
|
||||
* Return a {@link ResolvableType} for the specified {@link Method} parameter.
|
||||
* @param method the source method (must not be {@code null})
|
||||
* @param parameterIndex the parameter index
|
||||
* @return a {@code ResolvableType} for the specified method parameter
|
||||
* @return a {@link ResolvableType} for the specified method parameter
|
||||
* @see #forMethodParameter(Method, int, Class)
|
||||
* @see #forMethodParameter(MethodParameter)
|
||||
*/
|
||||
@@ -1282,13 +1279,13 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Method} parameter with a
|
||||
* Return a {@link ResolvableType} for the specified {@link Method} parameter with a
|
||||
* given implementation. Use this variant when the class that declares the method
|
||||
* includes generic parameter variables that are satisfied by the implementation class.
|
||||
* @param method the source method (must not be {@code null})
|
||||
* @param parameterIndex the parameter index
|
||||
* @param implementationClass the implementation class
|
||||
* @return a {@code ResolvableType} for the specified method parameter
|
||||
* @return a {@link ResolvableType} for the specified method parameter
|
||||
* @see #forMethodParameter(Method, int, Class)
|
||||
* @see #forMethodParameter(MethodParameter)
|
||||
*/
|
||||
@@ -1299,9 +1296,9 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link MethodParameter}.
|
||||
* Return a {@link ResolvableType} for the specified {@link MethodParameter}.
|
||||
* @param methodParameter the source method parameter (must not be {@code null})
|
||||
* @return a {@code ResolvableType} for the specified method parameter
|
||||
* @return a {@link ResolvableType} for the specified method parameter
|
||||
* @see #forMethodParameter(Method, int)
|
||||
*/
|
||||
public static ResolvableType forMethodParameter(MethodParameter methodParameter) {
|
||||
@@ -1309,12 +1306,12 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link MethodParameter} with a
|
||||
* Return a {@link ResolvableType} for the specified {@link MethodParameter} with a
|
||||
* given implementation type. Use this variant when the class that declares the method
|
||||
* includes generic parameter variables that are satisfied by the implementation type.
|
||||
* @param methodParameter the source method parameter (must not be {@code null})
|
||||
* @param implementationType the implementation type
|
||||
* @return a {@code ResolvableType} for the specified method parameter
|
||||
* @return a {@link ResolvableType} for the specified method parameter
|
||||
* @see #forMethodParameter(MethodParameter)
|
||||
*/
|
||||
public static ResolvableType forMethodParameter(MethodParameter methodParameter,
|
||||
@@ -1329,11 +1326,11 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link MethodParameter},
|
||||
* Return a {@link ResolvableType} for the specified {@link MethodParameter},
|
||||
* overriding the target type to resolve with a specific given type.
|
||||
* @param methodParameter the source method parameter (must not be {@code null})
|
||||
* @param targetType the type to resolve (a part of the method parameter's type)
|
||||
* @return a {@code ResolvableType} for the specified method parameter
|
||||
* @return a {@link ResolvableType} for the specified method parameter
|
||||
* @see #forMethodParameter(Method, int)
|
||||
*/
|
||||
public static ResolvableType forMethodParameter(MethodParameter methodParameter, @Nullable Type targetType) {
|
||||
@@ -1342,13 +1339,13 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link MethodParameter} at
|
||||
* Return a {@link ResolvableType} for the specified {@link MethodParameter} at
|
||||
* a specific nesting level, overriding the target type to resolve with a specific
|
||||
* given type.
|
||||
* @param methodParameter the source method parameter (must not be {@code null})
|
||||
* @param targetType the type to resolve (a part of the method parameter's type)
|
||||
* @param nestingLevel the nesting level to use
|
||||
* @return a {@code ResolvableType} for the specified method parameter
|
||||
* @return a {@link ResolvableType} for the specified method parameter
|
||||
* @since 5.2
|
||||
* @see #forMethodParameter(Method, int)
|
||||
*/
|
||||
@@ -1361,9 +1358,9 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} as an array of the specified {@code componentType}.
|
||||
* Return a {@link ResolvableType} as an array of the specified {@code componentType}.
|
||||
* @param componentType the component type
|
||||
* @return a {@code ResolvableType} as an array of the specified component type
|
||||
* @return a {@link ResolvableType} as an array of the specified component type
|
||||
*/
|
||||
public static ResolvableType forArrayComponent(ResolvableType componentType) {
|
||||
Assert.notNull(componentType, "Component type must not be null");
|
||||
@@ -1372,10 +1369,10 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Type}.
|
||||
* <p>Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}.
|
||||
* Return a {@link ResolvableType} for the specified {@link Type}.
|
||||
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
|
||||
* @param type the source type (potentially {@code null})
|
||||
* @return a {@code ResolvableType} for the specified {@link Type}
|
||||
* @return a {@link ResolvableType} for the specified {@link Type}
|
||||
* @see #forType(Type, ResolvableType)
|
||||
*/
|
||||
public static ResolvableType forType(@Nullable Type type) {
|
||||
@@ -1383,12 +1380,12 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Type} backed by the given
|
||||
* Return a {@link ResolvableType} for the specified {@link Type} backed by the given
|
||||
* owner type.
|
||||
* <p>Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}.
|
||||
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
|
||||
* @param type the source type or {@code null}
|
||||
* @param owner the owner type used to resolve variables
|
||||
* @return a {@code ResolvableType} for the specified {@link Type} and owner
|
||||
* @return a {@link ResolvableType} for the specified {@link Type} and owner
|
||||
* @see #forType(Type)
|
||||
*/
|
||||
public static ResolvableType forType(@Nullable Type type, @Nullable ResolvableType owner) {
|
||||
@@ -1401,10 +1398,10 @@ public class ResolvableType implements Serializable {
|
||||
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link ParameterizedTypeReference}.
|
||||
* <p>Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}.
|
||||
* Return a {@link ResolvableType} for the specified {@link ParameterizedTypeReference}.
|
||||
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
|
||||
* @param typeReference the reference to obtain the source type from
|
||||
* @return a {@code ResolvableType} for the specified {@link ParameterizedTypeReference}
|
||||
* @return a {@link ResolvableType} for the specified {@link ParameterizedTypeReference}
|
||||
* @since 4.3.12
|
||||
* @see #forType(Type)
|
||||
*/
|
||||
@@ -1413,23 +1410,23 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Type} backed by a given
|
||||
* Return a {@link ResolvableType} for the specified {@link Type} backed by a given
|
||||
* {@link VariableResolver}.
|
||||
* @param type the source type or {@code null}
|
||||
* @param variableResolver the variable resolver or {@code null}
|
||||
* @return a {@code ResolvableType} for the specified {@link Type} and {@link VariableResolver}
|
||||
* @return a {@link ResolvableType} for the specified {@link Type} and {@link VariableResolver}
|
||||
*/
|
||||
static ResolvableType forType(@Nullable Type type, @Nullable VariableResolver variableResolver) {
|
||||
return forType(type, null, variableResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Type} backed by a given
|
||||
* Return a {@link ResolvableType} for the specified {@link Type} backed by a given
|
||||
* {@link VariableResolver}.
|
||||
* @param type the source type or {@code null}
|
||||
* @param typeProvider the type provider or {@code null}
|
||||
* @param variableResolver the variable resolver or {@code null}
|
||||
* @return a {@code ResolvableType} for the specified {@link Type} and {@link VariableResolver}
|
||||
* @return a {@link ResolvableType} for the specified {@link Type} and {@link VariableResolver}
|
||||
*/
|
||||
static ResolvableType forType(
|
||||
@Nullable Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -159,7 +159,7 @@ final class SerializableTypeWrapper {
|
||||
|
||||
/**
|
||||
* Return the source of the type, or {@code null} if not known.
|
||||
* <p>The default implementation returns {@code null}.
|
||||
* <p>The default implementations returns {@code null}.
|
||||
*/
|
||||
@Nullable
|
||||
default Object getSource() {
|
||||
@@ -214,12 +214,7 @@ final class SerializableTypeWrapper {
|
||||
return result;
|
||||
}
|
||||
|
||||
Type type = this.provider.getType();
|
||||
if (type instanceof TypeVariable<?> && method.getName().equals("getName")) {
|
||||
// Avoid reflection for common comparison of type variables
|
||||
return ((TypeVariable<?>) type).getName();
|
||||
}
|
||||
return ReflectionUtils.invokeMethod(method, type, args);
|
||||
return ReflectionUtils.invokeMethod(method, this.provider.getType(), args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-27
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -757,7 +757,7 @@ public abstract class AnnotationUtils {
|
||||
* Google App Engine's late arrival of {@code TypeNotPresentExceptionProxy} for
|
||||
* {@code Class} values (instead of early {@code Class.getAnnotations() failure}).
|
||||
* <p>This method not failing indicates that {@link #getAnnotationAttributes(Annotation)}
|
||||
* won't fail either (when attempted later on).
|
||||
* won't failure either (when attempted later on).
|
||||
* @param annotation the annotation to validate
|
||||
* @throws IllegalStateException if a declared {@code Class} attribute could not be read
|
||||
* @since 4.3.15
|
||||
@@ -1059,7 +1059,8 @@ public abstract class AnnotationUtils {
|
||||
return null;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
handleValueRetrievalFailure(annotation, ex);
|
||||
rethrowAnnotationConfigurationException(ex);
|
||||
handleIntrospectionFailure(annotation.getClass(), ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1075,18 +1076,14 @@ public abstract class AnnotationUtils {
|
||||
* @return the value returned from the method invocation
|
||||
* @since 5.3.24
|
||||
*/
|
||||
@Nullable
|
||||
static Object invokeAnnotationMethod(Method method, @Nullable Object annotation) {
|
||||
if (annotation == null) {
|
||||
return null;
|
||||
}
|
||||
static Object invokeAnnotationMethod(Method method, Object annotation) {
|
||||
if (Proxy.isProxyClass(annotation.getClass())) {
|
||||
try {
|
||||
InvocationHandler handler = Proxy.getInvocationHandler(annotation);
|
||||
return handler.invoke(annotation, method, null);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Ignore and fall back to reflection below
|
||||
// ignore and fall back to reflection below
|
||||
}
|
||||
}
|
||||
return ReflectionUtils.invokeMethod(method, annotation);
|
||||
@@ -1120,32 +1117,20 @@ public abstract class AnnotationUtils {
|
||||
* @see #rethrowAnnotationConfigurationException
|
||||
* @see IntrospectionFailureLogger
|
||||
*/
|
||||
static void handleIntrospectionFailure(AnnotatedElement element, Throwable ex) {
|
||||
static void handleIntrospectionFailure(@Nullable AnnotatedElement element, Throwable ex) {
|
||||
rethrowAnnotationConfigurationException(ex);
|
||||
IntrospectionFailureLogger logger = IntrospectionFailureLogger.INFO;
|
||||
boolean meta = false;
|
||||
if (element instanceof Class && Annotation.class.isAssignableFrom((Class<?>) element)) {
|
||||
// Meta-annotation introspection failure
|
||||
// Meta-annotation or (default) value lookup on an annotation type
|
||||
logger = IntrospectionFailureLogger.DEBUG;
|
||||
meta = true;
|
||||
}
|
||||
if (logger.isEnabled()) {
|
||||
logger.log("Failed to " + (meta ? "meta-introspect annotation " : "introspect annotations on ") +
|
||||
element + ": " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the supplied value retrieval exception.
|
||||
* @param annotation the annotation instance from which to retrieve the value
|
||||
* @param ex the exception that we encountered
|
||||
* @see #handleIntrospectionFailure
|
||||
*/
|
||||
private static void handleValueRetrievalFailure(Annotation annotation, Throwable ex) {
|
||||
rethrowAnnotationConfigurationException(ex);
|
||||
IntrospectionFailureLogger logger = IntrospectionFailureLogger.INFO;
|
||||
if (logger.isEnabled()) {
|
||||
logger.log("Failed to retrieve value from " + annotation + ": " + ex);
|
||||
String message = meta ?
|
||||
"Failed to meta-introspect annotation " :
|
||||
"Failed to introspect annotations on ";
|
||||
logger.log(message + element + ": " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -339,10 +339,11 @@ abstract class AnnotationsScanner {
|
||||
|
||||
Method[] methods = baseTypeMethodsCache.get(baseType);
|
||||
if (methods == null) {
|
||||
methods = ReflectionUtils.getDeclaredMethods(baseType);
|
||||
boolean isInterface = baseType.isInterface();
|
||||
methods = isInterface ? baseType.getMethods() : ReflectionUtils.getDeclaredMethods(baseType);
|
||||
int cleared = 0;
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
if (Modifier.isPrivate(methods[i].getModifiers()) ||
|
||||
if ((!isInterface && Modifier.isPrivate(methods[i].getModifiers())) ||
|
||||
hasPlainJavaAnnotationsOnly(methods[i]) ||
|
||||
getDeclaredAnnotations(methods[i], false).length == 0) {
|
||||
methods[i] = null;
|
||||
@@ -456,7 +457,7 @@ abstract class AnnotationsScanner {
|
||||
for (int i = 0; i < annotations.length; i++) {
|
||||
Annotation annotation = annotations[i];
|
||||
if (isIgnorable(annotation.annotationType()) ||
|
||||
!AttributeMethods.forAnnotationType(annotation.annotationType()).canLoad(annotation)) {
|
||||
!AttributeMethods.forAnnotationType(annotation.annotationType()).isValid(annotation)) {
|
||||
annotations[i] = null;
|
||||
}
|
||||
else {
|
||||
|
||||
+8
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author 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,7 @@ final class AttributeMethods {
|
||||
if (m1 != null && m2 != null) {
|
||||
return m1.getName().compareTo(m2.getName());
|
||||
}
|
||||
return (m1 != null ? -1 : 1);
|
||||
return m1 != null ? -1 : 1;
|
||||
};
|
||||
|
||||
|
||||
@@ -87,26 +87,18 @@ final class AttributeMethods {
|
||||
/**
|
||||
* Determine if values from the given annotation can be safely accessed without
|
||||
* causing any {@link TypeNotPresentException TypeNotPresentExceptions}.
|
||||
* <p>This method is designed to cover Google App Engine's late arrival of such
|
||||
* exceptions for {@code Class} values (instead of the more typical early
|
||||
* {@code Class.getAnnotations() failure} on a regular JVM).
|
||||
* @param annotation the annotation to check
|
||||
* @return {@code true} if all values are present
|
||||
* @see #validate(Annotation)
|
||||
*/
|
||||
boolean canLoad(Annotation annotation) {
|
||||
boolean isValid(Annotation annotation) {
|
||||
assertAnnotation(annotation);
|
||||
for (int i = 0; i < size(); i++) {
|
||||
if (canThrowTypeNotPresentException(i)) {
|
||||
try {
|
||||
AnnotationUtils.invokeAnnotationMethod(get(i), annotation);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
// Plain invocation failure to expose -> leave up to attribute retrieval
|
||||
// (if any) where such invocation failure will be logged eventually.
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// TypeNotPresentException etc. -> annotation type not actually loadable.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -116,13 +108,13 @@ final class AttributeMethods {
|
||||
|
||||
/**
|
||||
* Check if values from the given annotation can be safely accessed without causing
|
||||
* any {@link TypeNotPresentException TypeNotPresentExceptions}.
|
||||
* <p>This method is designed to cover Google App Engine's late arrival of such
|
||||
* any {@link TypeNotPresentException TypeNotPresentExceptions}. In particular,
|
||||
* this method is designed to cover Google App Engine's late arrival of such
|
||||
* exceptions for {@code Class} values (instead of the more typical early
|
||||
* {@code Class.getAnnotations() failure} on a regular JVM).
|
||||
* {@code Class.getAnnotations() failure}).
|
||||
* @param annotation the annotation to validate
|
||||
* @throws IllegalStateException if a declared {@code Class} attribute could not be read
|
||||
* @see #canLoad(Annotation)
|
||||
* @see #isValid(Annotation)
|
||||
*/
|
||||
void validate(Annotation annotation) {
|
||||
assertAnnotation(annotation);
|
||||
@@ -131,9 +123,6 @@ final class AttributeMethods {
|
||||
try {
|
||||
AnnotationUtils.invokeAnnotationMethod(get(i), annotation);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException("Could not obtain annotation attribute value for " +
|
||||
get(i).getName() + " declared on " + annotation.annotationType(), ex);
|
||||
@@ -158,7 +147,7 @@ final class AttributeMethods {
|
||||
@Nullable
|
||||
Method get(String name) {
|
||||
int index = indexOf(name);
|
||||
return (index != -1 ? this.attributeMethods[index] : null);
|
||||
return index != -1 ? this.attributeMethods[index] : 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.
|
||||
@@ -476,7 +476,7 @@ public class TypeDescriptor implements Serializable {
|
||||
ObjectUtils.nullSafeEquals(getMapValueTypeDescriptor(), otherDesc.getMapValueTypeDescriptor()));
|
||||
}
|
||||
else {
|
||||
return Arrays.equals(getResolvableType().getGenerics(), otherDesc.getResolvableType().getGenerics());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,7 +523,7 @@ public class TypeDescriptor implements Serializable {
|
||||
/**
|
||||
* Create a new type descriptor for an object.
|
||||
* <p>Use this factory method to introspect a source object before asking the
|
||||
* conversion system to convert it to some other type.
|
||||
* conversion system to convert it to some another type.
|
||||
* <p>If the provided object is {@code null}, returns {@code null}, else calls
|
||||
* {@link #valueOf(Class)} to build a TypeDescriptor from the object's class.
|
||||
* @param source the source object
|
||||
|
||||
+3
-4
@@ -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.
|
||||
@@ -429,9 +429,8 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
|
||||
String filePath = new File(path).getAbsolutePath();
|
||||
int prefixIndex = filePath.indexOf(':');
|
||||
if (prefixIndex == 1) {
|
||||
// Possibly a drive prefix on Windows (for example, "c:"), so we prepend a slash
|
||||
// and convert the drive letter to uppercase for consistent duplicate detection.
|
||||
filePath = "/" + StringUtils.capitalize(filePath);
|
||||
// Possibly "c:" drive prefix on Windows, to be upper-cased for proper duplicate detection
|
||||
filePath = StringUtils.capitalize(filePath);
|
||||
}
|
||||
// # can appear in directories/filenames, java.net.URL should not treat it as a fragment
|
||||
filePath = StringUtils.replace(filePath, "#", "%23");
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -30,8 +30,6 @@ import org.springframework.util.DefaultPropertiesPersister;
|
||||
* "spring.xml.ignore" property.
|
||||
*
|
||||
* <p>This is the standard implementation used in Spring's resource support.
|
||||
* Only intended for internal use within the framework. For other purposes,
|
||||
* use its base class {@link DefaultPropertiesPersister} instead.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Sebastien Deleuze
|
||||
@@ -42,6 +40,7 @@ public class ResourcePropertiesPersister extends DefaultPropertiesPersister {
|
||||
/**
|
||||
* A convenient constant for a default {@code ResourcePropertiesPersister} instance,
|
||||
* as used in Spring's common resource support.
|
||||
* @since 5.3
|
||||
*/
|
||||
public static final ResourcePropertiesPersister INSTANCE = new ResourcePropertiesPersister();
|
||||
|
||||
|
||||
+17
-14
@@ -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.
|
||||
@@ -20,12 +20,12 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Implementation of {@link BackOff} that increases the back off period for each
|
||||
* retry attempt. When the interval has reached the {@linkplain #setMaxInterval
|
||||
* retry attempt. When the interval has reached the {@link #setMaxInterval(long)
|
||||
* max interval}, it is no longer increased. Stops retrying once the
|
||||
* {@linkplain #setMaxElapsedTime max elapsed time} has been reached.
|
||||
* {@link #setMaxElapsedTime(long) max elapsed time} has been reached.
|
||||
*
|
||||
* <p>Example: The default interval is {@value #DEFAULT_INITIAL_INTERVAL} ms;
|
||||
* the default multiplier is {@value #DEFAULT_MULTIPLIER}; and the default max
|
||||
* <p>Example: The default interval is {@value #DEFAULT_INITIAL_INTERVAL} ms,
|
||||
* the default multiplier is {@value #DEFAULT_MULTIPLIER}, and the default max
|
||||
* interval is {@value #DEFAULT_MAX_INTERVAL}. For 10 attempts the sequence will be
|
||||
* as follows:
|
||||
*
|
||||
@@ -44,9 +44,10 @@ import org.springframework.util.Assert;
|
||||
* 10 30000
|
||||
* </pre>
|
||||
*
|
||||
* <p>Note that the default max elapsed time is {@link Long#MAX_VALUE}.
|
||||
* Use {@link #setMaxElapsedTime} to limit the maximum length of time that an
|
||||
* instance should accumulate before returning {@link BackOffExecution#STOP}.
|
||||
* <p>Note that the default max elapsed time is {@link Long#MAX_VALUE}. Use
|
||||
* {@link #setMaxElapsedTime(long)} to limit the maximum length of time
|
||||
* that an instance should accumulate before returning
|
||||
* {@link BackOffExecution#STOP}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.1
|
||||
@@ -106,7 +107,7 @@ public class ExponentialBackOff implements BackOff {
|
||||
|
||||
|
||||
/**
|
||||
* Set the initial interval in milliseconds.
|
||||
* The initial interval in milliseconds.
|
||||
*/
|
||||
public void setInitialInterval(long initialInterval) {
|
||||
this.initialInterval = initialInterval;
|
||||
@@ -120,7 +121,7 @@ public class ExponentialBackOff implements BackOff {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value to multiply the current interval by for each retry attempt.
|
||||
* The value to multiply the current interval by for each retry attempt.
|
||||
*/
|
||||
public void setMultiplier(double multiplier) {
|
||||
checkMultiplier(multiplier);
|
||||
@@ -135,21 +136,21 @@ public class ExponentialBackOff implements BackOff {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum back off time in milliseconds.
|
||||
* The maximum back off time.
|
||||
*/
|
||||
public void setMaxInterval(long maxInterval) {
|
||||
this.maxInterval = maxInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum back off time in milliseconds.
|
||||
* Return the maximum back off time.
|
||||
*/
|
||||
public long getMaxInterval() {
|
||||
return this.maxInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum elapsed time in milliseconds after which a call to
|
||||
* The maximum elapsed time in milliseconds after which a call to
|
||||
* {@link BackOffExecution#nextBackOff()} returns {@link BackOffExecution#STOP}.
|
||||
*/
|
||||
public void setMaxElapsedTime(long maxElapsedTime) {
|
||||
@@ -183,9 +184,10 @@ public class ExponentialBackOff implements BackOff {
|
||||
|
||||
@Override
|
||||
public long nextBackOff() {
|
||||
if (this.currentElapsedTime >= getMaxElapsedTime()) {
|
||||
if (this.currentElapsedTime >= maxElapsedTime) {
|
||||
return STOP;
|
||||
}
|
||||
|
||||
long nextInterval = computeNextInterval();
|
||||
this.currentElapsedTime += nextInterval;
|
||||
return nextInterval;
|
||||
@@ -212,6 +214,7 @@ public class ExponentialBackOff implements BackOff {
|
||||
return Math.min(i, maxInterval);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("ExponentialBackOff{");
|
||||
|
||||
@@ -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.
|
||||
@@ -200,8 +200,8 @@ class ResolvableTypeTests {
|
||||
@Test
|
||||
void forFieldMustNotBeNull() throws Exception {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> ResolvableType.forField(null))
|
||||
.withMessage("Field must not be null");
|
||||
.isThrownBy(() -> ResolvableType.forField(null))
|
||||
.withMessage("Field must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -214,8 +214,8 @@ class ResolvableTypeTests {
|
||||
@Test
|
||||
void forConstructorParameterMustNotBeNull() throws Exception {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> ResolvableType.forConstructorParameter(null, 0))
|
||||
.withMessage("Constructor must not be null");
|
||||
.isThrownBy(() -> ResolvableType.forConstructorParameter(null, 0))
|
||||
.withMessage("Constructor must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -228,8 +228,8 @@ class ResolvableTypeTests {
|
||||
@Test
|
||||
void forMethodParameterByIndexMustNotBeNull() throws Exception {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> ResolvableType.forMethodParameter(null, 0))
|
||||
.withMessage("Method must not be null");
|
||||
.isThrownBy(() -> ResolvableType.forMethodParameter(null, 0))
|
||||
.withMessage("Method must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -268,8 +268,8 @@ class ResolvableTypeTests {
|
||||
@Test
|
||||
void forMethodParameterMustNotBeNull() throws Exception {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> ResolvableType.forMethodParameter(null))
|
||||
.withMessage("MethodParameter must not be null");
|
||||
.isThrownBy(() -> ResolvableType.forMethodParameter(null))
|
||||
.withMessage("MethodParameter must not be null");
|
||||
}
|
||||
|
||||
@Test // SPR-16210
|
||||
@@ -295,8 +295,8 @@ class ResolvableTypeTests {
|
||||
@Test
|
||||
void forMethodReturnMustNotBeNull() throws Exception {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> ResolvableType.forMethodReturnType(null))
|
||||
.withMessage("Method must not be null");
|
||||
.isThrownBy(() -> ResolvableType.forMethodReturnType(null))
|
||||
.withMessage("Method must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -343,7 +343,7 @@ class ResolvableTypeTests {
|
||||
ResolvableType type = ResolvableType.forField(field);
|
||||
assertThat(type.isArray()).isTrue();
|
||||
assertThat(type.getComponentType().getType())
|
||||
.isEqualTo(((Class) field.getGenericType()).getComponentType());
|
||||
.isEqualTo(((Class) field.getGenericType()).getComponentType());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -535,7 +535,7 @@ class ResolvableTypeTests {
|
||||
void getGenericsFromParameterizedType() throws Exception {
|
||||
ResolvableType type = ResolvableType.forClass(List.class, ExtendsList.class);
|
||||
ResolvableType[] generics = type.getGenerics();
|
||||
assertThat(generics).hasSize(1);
|
||||
assertThat(generics.length).isEqualTo(1);
|
||||
assertThat(generics[0].resolve()).isEqualTo(CharSequence.class);
|
||||
}
|
||||
|
||||
@@ -543,7 +543,7 @@ class ResolvableTypeTests {
|
||||
void getGenericsFromClass() throws Exception {
|
||||
ResolvableType type = ResolvableType.forClass(List.class);
|
||||
ResolvableType[] generics = type.getGenerics();
|
||||
assertThat(generics).hasSize(1);
|
||||
assertThat(generics.length).isEqualTo(1);
|
||||
assertThat(generics[0].getType().toString()).isEqualTo("E");
|
||||
}
|
||||
|
||||
@@ -558,7 +558,7 @@ class ResolvableTypeTests {
|
||||
void getResolvedGenerics() throws Exception {
|
||||
ResolvableType type = ResolvableType.forClass(List.class, ExtendsList.class);
|
||||
Class<?>[] generics = type.resolveGenerics();
|
||||
assertThat(generics).hasSize(1);
|
||||
assertThat(generics.length).isEqualTo(1);
|
||||
assertThat(generics[0]).isEqualTo(CharSequence.class);
|
||||
}
|
||||
|
||||
@@ -686,6 +686,7 @@ class ResolvableTypeTests {
|
||||
assertThat(type.resolve()).isEqualTo(CharSequence.class);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void resolveBoundedTypeVariableWildcardResult() throws Exception {
|
||||
ResolvableType type = ResolvableType.forMethodReturnType(Methods.class.getMethod("boundedTypeVariableWildcardResult"));
|
||||
@@ -700,26 +701,30 @@ class ResolvableTypeTests {
|
||||
|
||||
@Test
|
||||
void resolveTypeVariableFromSimpleInterfaceType() {
|
||||
ResolvableType type = ResolvableType.forClass(MySimpleInterfaceType.class).as(MyInterfaceType.class);
|
||||
ResolvableType type = ResolvableType.forClass(
|
||||
MySimpleInterfaceType.class).as(MyInterfaceType.class);
|
||||
assertThat(type.resolveGeneric()).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveTypeVariableFromSimpleCollectionInterfaceType() {
|
||||
ResolvableType type = ResolvableType.forClass(MyCollectionInterfaceType.class).as(MyInterfaceType.class);
|
||||
ResolvableType type = ResolvableType.forClass(
|
||||
MyCollectionInterfaceType.class).as(MyInterfaceType.class);
|
||||
assertThat(type.resolveGeneric()).isEqualTo(Collection.class);
|
||||
assertThat(type.resolveGeneric(0, 0)).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveTypeVariableFromSimpleSuperclassType() {
|
||||
ResolvableType type = ResolvableType.forClass(MySimpleSuperclassType.class).as(MySuperclassType.class);
|
||||
ResolvableType type = ResolvableType.forClass(
|
||||
MySimpleSuperclassType.class).as(MySuperclassType.class);
|
||||
assertThat(type.resolveGeneric()).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveTypeVariableFromSimpleCollectionSuperclassType() {
|
||||
ResolvableType type = ResolvableType.forClass(MyCollectionSuperclassType.class).as(MySuperclassType.class);
|
||||
ResolvableType type = ResolvableType.forClass(
|
||||
MyCollectionSuperclassType.class).as(MySuperclassType.class);
|
||||
assertThat(type.resolveGeneric()).isEqualTo(Collection.class);
|
||||
assertThat(type.resolveGeneric(0, 0)).isEqualTo(String.class);
|
||||
}
|
||||
@@ -746,7 +751,8 @@ class ResolvableTypeTests {
|
||||
void resolveTypeVariableFromSuperType() throws Exception {
|
||||
ResolvableType type = ResolvableType.forClass(ExtendsList.class);
|
||||
assertThat(type.resolve()).isEqualTo(ExtendsList.class);
|
||||
assertThat(type.asCollection().resolveGeneric()).isEqualTo(CharSequence.class);
|
||||
assertThat(type.asCollection().resolveGeneric())
|
||||
.isEqualTo(CharSequence.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -958,8 +964,8 @@ class ResolvableTypeTests {
|
||||
@Test
|
||||
void isAssignableFromMustNotBeNull() throws Exception {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> ResolvableType.forClass(Object.class).isAssignableFrom((ResolvableType) null))
|
||||
.withMessage("ResolvableType must not be null");
|
||||
.isThrownBy(() -> ResolvableType.forClass(Object.class).isAssignableFrom((ResolvableType) null))
|
||||
.withMessage("ResolvableType must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -998,7 +1004,6 @@ class ResolvableTypeTests {
|
||||
void isAssignableFromCannotBeResolved() throws Exception {
|
||||
ResolvableType objectType = ResolvableType.forClass(Object.class);
|
||||
ResolvableType unresolvableVariable = ResolvableType.forField(AssignmentBase.class.getField("o"));
|
||||
|
||||
assertThat(unresolvableVariable.resolve()).isNull();
|
||||
assertThatResolvableType(objectType).isAssignableFrom(unresolvableVariable);
|
||||
assertThatResolvableType(unresolvableVariable).isAssignableFrom(objectType);
|
||||
@@ -1215,9 +1220,9 @@ class ResolvableTypeTests {
|
||||
@Test
|
||||
void forClassWithMismatchedGenerics() throws Exception {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> ResolvableType.forClassWithGenerics(Map.class, Integer.class))
|
||||
.withMessageContaining("Mismatched number of generics specified for")
|
||||
.withMessageContaining("java.util.Map<K,V>");
|
||||
.isThrownBy(() -> ResolvableType.forClassWithGenerics(Map.class, Integer.class))
|
||||
.withMessageContaining("Mismatched number of generics specified for")
|
||||
.withMessageContaining("java.util.Map<K,V>");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1272,7 +1277,7 @@ class ResolvableTypeTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasUnresolvableGenericsWhenImplementingRawInterface() throws Exception {
|
||||
void hasUnresolvableGenericsWhenImplementesRawInterface() throws Exception {
|
||||
ResolvableType type = ResolvableType.forClass(MySimpleInterfaceTypeWithImplementsRaw.class);
|
||||
for (ResolvableType generic : type.getGenerics()) {
|
||||
assertThat(generic.resolve()).isNotNull();
|
||||
@@ -1302,7 +1307,7 @@ class ResolvableTypeTests {
|
||||
Type type = resolvableType.getType();
|
||||
assertThat(type).isInstanceOf(ParameterizedType.class);
|
||||
assertThat(((ParameterizedType) type).getRawType()).isEqualTo(Callable.class);
|
||||
assertThat(((ParameterizedType) type).getActualTypeArguments()).hasSize(1);
|
||||
assertThat(((ParameterizedType) type).getActualTypeArguments().length).isEqualTo(1);
|
||||
assertThat(((ParameterizedType) type).getActualTypeArguments()[0]).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
|
||||
+44
-33
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -43,45 +43,55 @@ class AnnotationIntrospectionFailureTests {
|
||||
|
||||
@Test
|
||||
void filteredTypeThrowsTypeNotPresentException() throws Exception {
|
||||
FilteringClassLoader classLoader = new FilteringClassLoader(getClass().getClassLoader());
|
||||
Class<?> withAnnotation = ClassUtils.forName(WithExampleAnnotation.class.getName(), classLoader);
|
||||
Annotation annotation = withAnnotation.getAnnotations()[0];
|
||||
FilteringClassLoader classLoader = new FilteringClassLoader(
|
||||
getClass().getClassLoader());
|
||||
Class<?> withExampleAnnotation = ClassUtils.forName(
|
||||
WithExampleAnnotation.class.getName(), classLoader);
|
||||
Annotation annotation = withExampleAnnotation.getAnnotations()[0];
|
||||
Method method = annotation.annotationType().getMethod("value");
|
||||
method.setAccessible(true);
|
||||
assertThatExceptionOfType(TypeNotPresentException.class)
|
||||
.isThrownBy(() -> ReflectionUtils.invokeMethod(method, annotation))
|
||||
.withCauseInstanceOf(ClassNotFoundException.class);
|
||||
assertThatExceptionOfType(TypeNotPresentException.class).isThrownBy(() ->
|
||||
ReflectionUtils.invokeMethod(method, annotation))
|
||||
.withCauseInstanceOf(ClassNotFoundException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void filteredTypeInMetaAnnotationWhenUsingAnnotatedElementUtilsHandlesException() throws Exception {
|
||||
FilteringClassLoader classLoader = new FilteringClassLoader(getClass().getClassLoader());
|
||||
Class<?> withAnnotation = ClassUtils.forName(WithExampleMetaAnnotation.class.getName(), classLoader);
|
||||
Class<Annotation> annotationClass = (Class<Annotation>)
|
||||
ClassUtils.forName(ExampleAnnotation.class.getName(), classLoader);
|
||||
Class<Annotation> metaAnnotationClass = (Class<Annotation>)
|
||||
ClassUtils.forName(ExampleMetaAnnotation.class.getName(), classLoader);
|
||||
assertThat(AnnotatedElementUtils.getMergedAnnotationAttributes(withAnnotation, annotationClass)).isNull();
|
||||
assertThat(AnnotatedElementUtils.getMergedAnnotationAttributes(withAnnotation, metaAnnotationClass)).isNull();
|
||||
assertThat(AnnotatedElementUtils.hasAnnotation(withAnnotation, annotationClass)).isFalse();
|
||||
assertThat(AnnotatedElementUtils.hasAnnotation(withAnnotation, metaAnnotationClass)).isFalse();
|
||||
FilteringClassLoader classLoader = new FilteringClassLoader(
|
||||
getClass().getClassLoader());
|
||||
Class<?> withExampleMetaAnnotation = ClassUtils.forName(
|
||||
WithExampleMetaAnnotation.class.getName(), classLoader);
|
||||
Class<Annotation> exampleAnnotationClass = (Class<Annotation>) ClassUtils.forName(
|
||||
ExampleAnnotation.class.getName(), classLoader);
|
||||
Class<Annotation> exampleMetaAnnotationClass = (Class<Annotation>) ClassUtils.forName(
|
||||
ExampleMetaAnnotation.class.getName(), classLoader);
|
||||
assertThat(AnnotatedElementUtils.getMergedAnnotationAttributes(
|
||||
withExampleMetaAnnotation, exampleAnnotationClass)).isNull();
|
||||
assertThat(AnnotatedElementUtils.getMergedAnnotationAttributes(
|
||||
withExampleMetaAnnotation, exampleMetaAnnotationClass)).isNull();
|
||||
assertThat(AnnotatedElementUtils.hasAnnotation(withExampleMetaAnnotation,
|
||||
exampleAnnotationClass)).isFalse();
|
||||
assertThat(AnnotatedElementUtils.hasAnnotation(withExampleMetaAnnotation,
|
||||
exampleMetaAnnotationClass)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void filteredTypeInMetaAnnotationWhenUsingMergedAnnotationsHandlesException() throws Exception {
|
||||
FilteringClassLoader classLoader = new FilteringClassLoader(getClass().getClassLoader());
|
||||
Class<?> withAnnotation = ClassUtils.forName(WithExampleMetaAnnotation.class.getName(), classLoader);
|
||||
Class<Annotation> annotationClass = (Class<Annotation>)
|
||||
ClassUtils.forName(ExampleAnnotation.class.getName(), classLoader);
|
||||
Class<Annotation> metaAnnotationClass = (Class<Annotation>)
|
||||
ClassUtils.forName(ExampleMetaAnnotation.class.getName(), classLoader);
|
||||
MergedAnnotations annotations = MergedAnnotations.from(withAnnotation);
|
||||
assertThat(annotations.get(annotationClass).isPresent()).isFalse();
|
||||
assertThat(annotations.get(metaAnnotationClass).isPresent()).isFalse();
|
||||
assertThat(annotations.isPresent(metaAnnotationClass)).isFalse();
|
||||
assertThat(annotations.isPresent(annotationClass)).isFalse();
|
||||
FilteringClassLoader classLoader = new FilteringClassLoader(
|
||||
getClass().getClassLoader());
|
||||
Class<?> withExampleMetaAnnotation = ClassUtils.forName(
|
||||
WithExampleMetaAnnotation.class.getName(), classLoader);
|
||||
Class<Annotation> exampleAnnotationClass = (Class<Annotation>) ClassUtils.forName(
|
||||
ExampleAnnotation.class.getName(), classLoader);
|
||||
Class<Annotation> exampleMetaAnnotationClass = (Class<Annotation>) ClassUtils.forName(
|
||||
ExampleMetaAnnotation.class.getName(), classLoader);
|
||||
MergedAnnotations annotations = MergedAnnotations.from(withExampleMetaAnnotation);
|
||||
assertThat(annotations.get(exampleAnnotationClass).isPresent()).isFalse();
|
||||
assertThat(annotations.get(exampleMetaAnnotationClass).isPresent()).isFalse();
|
||||
assertThat(annotations.isPresent(exampleMetaAnnotationClass)).isFalse();
|
||||
assertThat(annotations.isPresent(exampleAnnotationClass)).isFalse();
|
||||
}
|
||||
|
||||
|
||||
@@ -93,16 +103,17 @@ class AnnotationIntrospectionFailureTests {
|
||||
|
||||
@Override
|
||||
protected boolean isEligibleForOverriding(String className) {
|
||||
return className.startsWith(AnnotationIntrospectionFailureTests.class.getName()) ||
|
||||
className.startsWith("jdk.internal");
|
||||
return className.startsWith(
|
||||
AnnotationIntrospectionFailureTests.class.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> loadClassForOverriding(String name) throws ClassNotFoundException {
|
||||
if (name.contains("Filtered") || name.startsWith("jdk.internal")) {
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
if (name.startsWith(AnnotationIntrospectionFailureTests.class.getName()) &&
|
||||
name.contains("Filtered")) {
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
return super.loadClassForOverriding(name);
|
||||
return super.loadClass(name, resolve);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-36
@@ -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.
|
||||
@@ -194,7 +194,7 @@ class AnnotationsScannerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void typeHierarchyStrategyOnClassWhenHasSingleInterfaceScansInterfaces() {
|
||||
void typeHierarchyStrategyOnClassWhenHasInterfaceDoesNotIncludeInterfaces() {
|
||||
Class<?> source = WithSingleInterface.class;
|
||||
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY)).containsExactly(
|
||||
"0:TestAnnotation1", "1:TestAnnotation2", "1:TestInheritedAnnotation2");
|
||||
@@ -350,19 +350,10 @@ class AnnotationsScannerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void typeHierarchyStrategyOnMethodWhenHasInterfaceScansInterfaces() {
|
||||
void typeHierarchyStrategyOnMethodWhenHasInterfaceDoesNotIncludeInterfaces() {
|
||||
Method source = methodFrom(WithSingleInterface.class);
|
||||
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY)).containsExactly(
|
||||
"0:TestAnnotation1", "1:TestAnnotation2", "1:TestInheritedAnnotation2");
|
||||
|
||||
source = methodFrom(Hello1Impl.class);
|
||||
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY)).containsExactly("1:TestAnnotation1");
|
||||
}
|
||||
|
||||
@Test // gh-31803
|
||||
void typeHierarchyStrategyOnMethodWhenHasInterfaceHierarchyScansInterfacesOnlyOnce() {
|
||||
Method source = methodFrom(Hello2Impl.class);
|
||||
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY)).containsExactly("1:TestAnnotation1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -672,30 +663,6 @@ class AnnotationsScannerTests {
|
||||
}
|
||||
}
|
||||
|
||||
interface Hello1 {
|
||||
|
||||
@TestAnnotation1
|
||||
void method();
|
||||
}
|
||||
|
||||
interface Hello2 extends Hello1 {
|
||||
}
|
||||
|
||||
static class Hello1Impl implements Hello1 {
|
||||
|
||||
@Override
|
||||
public void method() {
|
||||
}
|
||||
}
|
||||
|
||||
static class Hello2Impl implements Hello2 {
|
||||
|
||||
@Override
|
||||
public void method() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@TestAnnotation2
|
||||
@TestInheritedAnnotation2
|
||||
static class HierarchySuperclass extends HierarchySuperSuperclass {
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -112,7 +112,7 @@ class AttributeMethodsTests {
|
||||
ClassValue annotation = mockAnnotation(ClassValue.class);
|
||||
given(annotation.value()).willThrow(TypeNotPresentException.class);
|
||||
AttributeMethods attributes = AttributeMethods.forAnnotationType(annotation.annotationType());
|
||||
assertThat(attributes.canLoad(annotation)).isFalse();
|
||||
assertThat(attributes.isValid(annotation)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -121,7 +121,7 @@ class AttributeMethodsTests {
|
||||
ClassValue annotation = mock(ClassValue.class);
|
||||
given(annotation.value()).willReturn((Class) InputStream.class);
|
||||
AttributeMethods attributes = AttributeMethods.forAnnotationType(annotation.annotationType());
|
||||
assertThat(attributes.canLoad(annotation)).isTrue();
|
||||
assertThat(attributes.isValid(annotation)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+393
-324
File diff suppressed because it is too large
Load Diff
+36
-49
@@ -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.
|
||||
@@ -34,13 +34,11 @@ import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
@@ -67,7 +65,7 @@ class TypeDescriptorTests {
|
||||
assertThat(desc.getName()).isEqualTo("int");
|
||||
assertThat(desc.toString()).isEqualTo("int");
|
||||
assertThat(desc.isPrimitive()).isTrue();
|
||||
assertThat(desc.getAnnotations()).isEmpty();
|
||||
assertThat(desc.getAnnotations().length).isEqualTo(0);
|
||||
assertThat(desc.isCollection()).isFalse();
|
||||
assertThat(desc.isMap()).isFalse();
|
||||
}
|
||||
@@ -79,8 +77,8 @@ class TypeDescriptorTests {
|
||||
assertThat(desc.getObjectType()).isEqualTo(String.class);
|
||||
assertThat(desc.getName()).isEqualTo("java.lang.String");
|
||||
assertThat(desc.toString()).isEqualTo("java.lang.String");
|
||||
assertThat(desc.isPrimitive()).isFalse();
|
||||
assertThat(desc.getAnnotations()).isEmpty();
|
||||
assertThat(!desc.isPrimitive()).isTrue();
|
||||
assertThat(desc.getAnnotations().length).isEqualTo(0);
|
||||
assertThat(desc.isCollection()).isFalse();
|
||||
assertThat(desc.isArray()).isFalse();
|
||||
assertThat(desc.isMap()).isFalse();
|
||||
@@ -94,8 +92,8 @@ class TypeDescriptorTests {
|
||||
assertThat(desc.getObjectType()).isEqualTo(List.class);
|
||||
assertThat(desc.getName()).isEqualTo("java.util.List");
|
||||
assertThat(desc.toString()).isEqualTo("java.util.List<java.util.List<java.util.Map<java.lang.Integer, java.lang.Enum<?>>>>");
|
||||
assertThat(desc.isPrimitive()).isFalse();
|
||||
assertThat(desc.getAnnotations()).isEmpty();
|
||||
assertThat(!desc.isPrimitive()).isTrue();
|
||||
assertThat(desc.getAnnotations().length).isEqualTo(0);
|
||||
assertThat(desc.isCollection()).isTrue();
|
||||
assertThat(desc.isArray()).isFalse();
|
||||
assertThat(desc.getElementTypeDescriptor().getType()).isEqualTo(List.class);
|
||||
@@ -115,8 +113,8 @@ class TypeDescriptorTests {
|
||||
assertThat(desc.getObjectType()).isEqualTo(List.class);
|
||||
assertThat(desc.getName()).isEqualTo("java.util.List");
|
||||
assertThat(desc.toString()).isEqualTo("java.util.List<?>");
|
||||
assertThat(desc.isPrimitive()).isFalse();
|
||||
assertThat(desc.getAnnotations()).isEmpty();
|
||||
assertThat(!desc.isPrimitive()).isTrue();
|
||||
assertThat(desc.getAnnotations().length).isEqualTo(0);
|
||||
assertThat(desc.isCollection()).isTrue();
|
||||
assertThat(desc.isArray()).isFalse();
|
||||
assertThat((Object) desc.getElementTypeDescriptor()).isNull();
|
||||
@@ -131,8 +129,8 @@ class TypeDescriptorTests {
|
||||
assertThat(desc.getObjectType()).isEqualTo(Integer[].class);
|
||||
assertThat(desc.getName()).isEqualTo("java.lang.Integer[]");
|
||||
assertThat(desc.toString()).isEqualTo("java.lang.Integer[]");
|
||||
assertThat(desc.isPrimitive()).isFalse();
|
||||
assertThat(desc.getAnnotations()).isEmpty();
|
||||
assertThat(!desc.isPrimitive()).isTrue();
|
||||
assertThat(desc.getAnnotations().length).isEqualTo(0);
|
||||
assertThat(desc.isCollection()).isFalse();
|
||||
assertThat(desc.isArray()).isTrue();
|
||||
assertThat(desc.getElementTypeDescriptor().getType()).isEqualTo(Integer.class);
|
||||
@@ -148,8 +146,8 @@ class TypeDescriptorTests {
|
||||
assertThat(desc.getObjectType()).isEqualTo(Map.class);
|
||||
assertThat(desc.getName()).isEqualTo("java.util.Map");
|
||||
assertThat(desc.toString()).isEqualTo("java.util.Map<java.lang.Integer, java.util.List<java.lang.String>>");
|
||||
assertThat(desc.isPrimitive()).isFalse();
|
||||
assertThat(desc.getAnnotations()).isEmpty();
|
||||
assertThat(!desc.isPrimitive()).isTrue();
|
||||
assertThat(desc.getAnnotations().length).isEqualTo(0);
|
||||
assertThat(desc.isCollection()).isFalse();
|
||||
assertThat(desc.isArray()).isFalse();
|
||||
assertThat(desc.isMap()).isTrue();
|
||||
@@ -164,7 +162,7 @@ class TypeDescriptorTests {
|
||||
void parameterAnnotated() throws Exception {
|
||||
TypeDescriptor t1 = new TypeDescriptor(new MethodParameter(getClass().getMethod("testAnnotatedMethod", String.class), 0));
|
||||
assertThat(t1.getType()).isEqualTo(String.class);
|
||||
assertThat(t1.getAnnotations()).hasSize(1);
|
||||
assertThat(t1.getAnnotations().length).isEqualTo(1);
|
||||
assertThat(t1.getAnnotation(ParameterAnnotation.class)).isNotNull();
|
||||
assertThat(t1.hasAnnotation(ParameterAnnotation.class)).isTrue();
|
||||
assertThat(t1.getAnnotation(ParameterAnnotation.class).value()).isEqualTo(123);
|
||||
@@ -337,7 +335,7 @@ class TypeDescriptorTests {
|
||||
@Test
|
||||
void fieldAnnotated() throws Exception {
|
||||
TypeDescriptor typeDescriptor = new TypeDescriptor(getClass().getField("fieldAnnotated"));
|
||||
assertThat(typeDescriptor.getAnnotations()).hasSize(1);
|
||||
assertThat(typeDescriptor.getAnnotations().length).isEqualTo(1);
|
||||
assertThat(typeDescriptor.getAnnotation(FieldAnnotation.class)).isNotNull();
|
||||
}
|
||||
|
||||
@@ -464,8 +462,8 @@ class TypeDescriptorTests {
|
||||
assertThat(desc.getObjectType()).isEqualTo(List.class);
|
||||
assertThat(desc.getName()).isEqualTo("java.util.List");
|
||||
assertThat(desc.toString()).isEqualTo("java.util.List<java.lang.Integer>");
|
||||
assertThat(desc.isPrimitive()).isFalse();
|
||||
assertThat(desc.getAnnotations()).isEmpty();
|
||||
assertThat(!desc.isPrimitive()).isTrue();
|
||||
assertThat(desc.getAnnotations().length).isEqualTo(0);
|
||||
assertThat(desc.isCollection()).isTrue();
|
||||
assertThat(desc.isArray()).isFalse();
|
||||
assertThat(desc.getElementTypeDescriptor().getType()).isEqualTo(Integer.class);
|
||||
@@ -480,8 +478,8 @@ class TypeDescriptorTests {
|
||||
assertThat(desc.getObjectType()).isEqualTo(List.class);
|
||||
assertThat(desc.getName()).isEqualTo("java.util.List");
|
||||
assertThat(desc.toString()).isEqualTo("java.util.List<java.util.List<java.lang.Integer>>");
|
||||
assertThat(desc.isPrimitive()).isFalse();
|
||||
assertThat(desc.getAnnotations()).isEmpty();
|
||||
assertThat(!desc.isPrimitive()).isTrue();
|
||||
assertThat(desc.getAnnotations().length).isEqualTo(0);
|
||||
assertThat(desc.isCollection()).isTrue();
|
||||
assertThat(desc.isArray()).isFalse();
|
||||
assertThat(desc.getElementTypeDescriptor().getType()).isEqualTo(List.class);
|
||||
@@ -496,8 +494,8 @@ class TypeDescriptorTests {
|
||||
assertThat(desc.getObjectType()).isEqualTo(Map.class);
|
||||
assertThat(desc.getName()).isEqualTo("java.util.Map");
|
||||
assertThat(desc.toString()).isEqualTo("java.util.Map<java.lang.String, java.lang.Integer>");
|
||||
assertThat(desc.isPrimitive()).isFalse();
|
||||
assertThat(desc.getAnnotations()).isEmpty();
|
||||
assertThat(!desc.isPrimitive()).isTrue();
|
||||
assertThat(desc.getAnnotations().length).isEqualTo(0);
|
||||
assertThat(desc.isCollection()).isFalse();
|
||||
assertThat(desc.isArray()).isFalse();
|
||||
assertThat(desc.isMap()).isTrue();
|
||||
@@ -513,8 +511,8 @@ class TypeDescriptorTests {
|
||||
assertThat(desc.getObjectType()).isEqualTo(Map.class);
|
||||
assertThat(desc.getName()).isEqualTo("java.util.Map");
|
||||
assertThat(desc.toString()).isEqualTo("java.util.Map<java.lang.String, java.util.Map<java.lang.String, java.lang.Integer>>");
|
||||
assertThat(desc.isPrimitive()).isFalse();
|
||||
assertThat(desc.getAnnotations()).isEmpty();
|
||||
assertThat(!desc.isPrimitive()).isTrue();
|
||||
assertThat(desc.getAnnotations().length).isEqualTo(0);
|
||||
assertThat(desc.isCollection()).isFalse();
|
||||
assertThat(desc.isArray()).isFalse();
|
||||
assertThat(desc.isMap()).isTrue();
|
||||
@@ -526,7 +524,7 @@ class TypeDescriptorTests {
|
||||
@Test
|
||||
void narrow() {
|
||||
TypeDescriptor desc = TypeDescriptor.valueOf(Number.class);
|
||||
Integer value = 3;
|
||||
Integer value = Integer.valueOf(3);
|
||||
desc = desc.narrow(value);
|
||||
assertThat(desc.getType()).isEqualTo(Integer.class);
|
||||
}
|
||||
@@ -534,7 +532,7 @@ class TypeDescriptorTests {
|
||||
@Test
|
||||
void elementType() {
|
||||
TypeDescriptor desc = TypeDescriptor.valueOf(List.class);
|
||||
Integer value = 3;
|
||||
Integer value = Integer.valueOf(3);
|
||||
desc = desc.elementTypeDescriptor(value);
|
||||
assertThat(desc.getType()).isEqualTo(Integer.class);
|
||||
}
|
||||
@@ -552,7 +550,7 @@ class TypeDescriptorTests {
|
||||
@Test
|
||||
void mapKeyType() {
|
||||
TypeDescriptor desc = TypeDescriptor.valueOf(Map.class);
|
||||
Integer value = 3;
|
||||
Integer value = Integer.valueOf(3);
|
||||
desc = desc.getMapKeyTypeDescriptor(value);
|
||||
assertThat(desc.getType()).isEqualTo(Integer.class);
|
||||
}
|
||||
@@ -570,7 +568,7 @@ class TypeDescriptorTests {
|
||||
@Test
|
||||
void mapValueType() {
|
||||
TypeDescriptor desc = TypeDescriptor.valueOf(Map.class);
|
||||
Integer value = 3;
|
||||
Integer value = Integer.valueOf(3);
|
||||
desc = desc.getMapValueTypeDescriptor(value);
|
||||
assertThat(desc.getType()).isEqualTo(Integer.class);
|
||||
}
|
||||
@@ -665,12 +663,12 @@ class TypeDescriptorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void upcast() throws Exception {
|
||||
void upCast() throws Exception {
|
||||
Property property = new Property(getClass(), getClass().getMethod("getProperty"),
|
||||
getClass().getMethod("setProperty", Map.class));
|
||||
TypeDescriptor typeDescriptor = new TypeDescriptor(property);
|
||||
TypeDescriptor upcast = typeDescriptor.upcast(Object.class);
|
||||
assertThat(upcast.getAnnotation(MethodAnnotation1.class)).isNotNull();
|
||||
TypeDescriptor upCast = typeDescriptor.upcast(Object.class);
|
||||
assertThat(upCast.getAnnotation(MethodAnnotation1.class) != null).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -684,7 +682,7 @@ class TypeDescriptorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void elementTypeForCollectionSubclass() {
|
||||
void elementTypeForCollectionSubclass() throws Exception {
|
||||
@SuppressWarnings("serial")
|
||||
class CustomSet extends HashSet<String> {
|
||||
}
|
||||
@@ -694,7 +692,7 @@ class TypeDescriptorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void elementTypeForMapSubclass() {
|
||||
void elementTypeForMapSubclass() throws Exception {
|
||||
@SuppressWarnings("serial")
|
||||
class CustomMap extends HashMap<String, Integer> {
|
||||
}
|
||||
@@ -706,7 +704,7 @@ class TypeDescriptorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void createMapArray() {
|
||||
void createMapArray() throws Exception {
|
||||
TypeDescriptor mapType = TypeDescriptor.map(
|
||||
LinkedHashMap.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class));
|
||||
TypeDescriptor arrayType = TypeDescriptor.array(mapType);
|
||||
@@ -715,13 +713,13 @@ class TypeDescriptorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void createStringArray() {
|
||||
void createStringArray() throws Exception {
|
||||
TypeDescriptor arrayType = TypeDescriptor.array(TypeDescriptor.valueOf(String.class));
|
||||
assertThat(TypeDescriptor.valueOf(String[].class)).isEqualTo(arrayType);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createNullArray() {
|
||||
void createNullArray() throws Exception {
|
||||
assertThat((Object) TypeDescriptor.array(null)).isNull();
|
||||
}
|
||||
|
||||
@@ -738,13 +736,13 @@ class TypeDescriptorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void createCollectionWithNullElement() {
|
||||
void createCollectionWithNullElement() throws Exception {
|
||||
TypeDescriptor typeDescriptor = TypeDescriptor.collection(List.class, null);
|
||||
assertThat(typeDescriptor.getElementTypeDescriptor()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void createMapWithNullElements() {
|
||||
void createMapWithNullElements() throws Exception {
|
||||
TypeDescriptor typeDescriptor = TypeDescriptor.map(LinkedHashMap.class, null, null);
|
||||
assertThat(typeDescriptor.getMapKeyTypeDescriptor()).isNull();
|
||||
assertThat(typeDescriptor.getMapValueTypeDescriptor()).isNull();
|
||||
@@ -759,17 +757,6 @@ class TypeDescriptorTests {
|
||||
assertThat(TypeDescriptor.valueOf(Integer.class).getSource()).isEqualTo(Integer.class);
|
||||
}
|
||||
|
||||
@Test // gh-31672
|
||||
void equalityWithGenerics() {
|
||||
ResolvableType rt1 = ResolvableType.forClassWithGenerics(Optional.class, Integer.class);
|
||||
ResolvableType rt2 = ResolvableType.forClassWithGenerics(Optional.class, String.class);
|
||||
|
||||
TypeDescriptor td1 = new TypeDescriptor(rt1, null, null);
|
||||
TypeDescriptor td2 = new TypeDescriptor(rt2, null, null);
|
||||
|
||||
assertThat(td1).isNotEqualTo(td2);
|
||||
}
|
||||
|
||||
|
||||
// Methods designed for test introspection
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -21,39 +21,13 @@ import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ConcurrentLruCache}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
class ConcurrentLruCacheTests {
|
||||
|
||||
private final ConcurrentLruCache<String, String> cache = new ConcurrentLruCache<>(2, key -> key + "value");
|
||||
|
||||
|
||||
@Test
|
||||
void zeroCapacity() {
|
||||
ConcurrentLruCache<String, String> cache = new ConcurrentLruCache<>(0, key -> key + "value");
|
||||
|
||||
assertThat(cache.sizeLimit()).isZero();
|
||||
assertThat(cache.size()).isZero();
|
||||
|
||||
assertThat(cache.get("k1")).isEqualTo("k1value");
|
||||
assertThat(cache.size()).isZero();
|
||||
assertThat(cache.contains("k1")).isFalse();
|
||||
|
||||
assertThat(cache.get("k2")).isEqualTo("k2value");
|
||||
assertThat(cache.size()).isZero();
|
||||
assertThat(cache.contains("k1")).isFalse();
|
||||
assertThat(cache.contains("k2")).isFalse();
|
||||
|
||||
assertThat(cache.get("k3")).isEqualTo("k3value");
|
||||
assertThat(cache.size()).isZero();
|
||||
assertThat(cache.contains("k1")).isFalse();
|
||||
assertThat(cache.contains("k2")).isFalse();
|
||||
assertThat(cache.contains("k3")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAndSize() {
|
||||
assertThat(this.cache.sizeLimit()).isEqualTo(2);
|
||||
|
||||
+36
-35
@@ -117,7 +117,6 @@ public class ReflectiveMethodResolver implements MethodResolver {
|
||||
TypeConverter typeConverter = context.getTypeConverter();
|
||||
Class<?> type = (targetObject instanceof Class ? (Class<?>) targetObject : targetObject.getClass());
|
||||
ArrayList<Method> methods = new ArrayList<>(getMethods(type, targetObject));
|
||||
methods.removeIf(method -> !method.getName().equals(name));
|
||||
|
||||
// If a filter is registered for this type, call it
|
||||
MethodFilter filter = (this.filters != null ? this.filters.get(type) : null);
|
||||
@@ -161,46 +160,48 @@ public class ReflectiveMethodResolver implements MethodResolver {
|
||||
boolean multipleOptions = false;
|
||||
|
||||
for (Method method : methodsToIterate) {
|
||||
int paramCount = method.getParameterCount();
|
||||
List<TypeDescriptor> paramDescriptors = new ArrayList<>(paramCount);
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
paramDescriptors.add(new TypeDescriptor(new MethodParameter(method, i)));
|
||||
}
|
||||
ReflectionHelper.ArgumentsMatchInfo matchInfo = null;
|
||||
if (method.isVarArgs() && argumentTypes.size() >= (paramCount - 1)) {
|
||||
// *sigh* complicated
|
||||
matchInfo = ReflectionHelper.compareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter);
|
||||
}
|
||||
else if (paramCount == argumentTypes.size()) {
|
||||
// Name and parameter number match, check the arguments
|
||||
matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter);
|
||||
}
|
||||
if (matchInfo != null) {
|
||||
if (matchInfo.isExactMatch()) {
|
||||
return new ReflectiveMethodExecutor(method, type);
|
||||
if (method.getName().equals(name)) {
|
||||
int paramCount = method.getParameterCount();
|
||||
List<TypeDescriptor> paramDescriptors = new ArrayList<>(paramCount);
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
paramDescriptors.add(new TypeDescriptor(new MethodParameter(method, i)));
|
||||
}
|
||||
else if (matchInfo.isCloseMatch()) {
|
||||
if (this.useDistance) {
|
||||
int matchDistance = ReflectionHelper.getTypeDifferenceWeight(paramDescriptors, argumentTypes);
|
||||
if (closeMatch == null || matchDistance < closeMatchDistance) {
|
||||
// This is a better match...
|
||||
closeMatch = method;
|
||||
closeMatchDistance = matchDistance;
|
||||
ReflectionHelper.ArgumentsMatchInfo matchInfo = null;
|
||||
if (method.isVarArgs() && argumentTypes.size() >= (paramCount - 1)) {
|
||||
// *sigh* complicated
|
||||
matchInfo = ReflectionHelper.compareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter);
|
||||
}
|
||||
else if (paramCount == argumentTypes.size()) {
|
||||
// Name and parameter number match, check the arguments
|
||||
matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter);
|
||||
}
|
||||
if (matchInfo != null) {
|
||||
if (matchInfo.isExactMatch()) {
|
||||
return new ReflectiveMethodExecutor(method, type);
|
||||
}
|
||||
else if (matchInfo.isCloseMatch()) {
|
||||
if (this.useDistance) {
|
||||
int matchDistance = ReflectionHelper.getTypeDifferenceWeight(paramDescriptors, argumentTypes);
|
||||
if (closeMatch == null || matchDistance < closeMatchDistance) {
|
||||
// This is a better match...
|
||||
closeMatch = method;
|
||||
closeMatchDistance = matchDistance;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Take this as a close match if there isn't one already
|
||||
if (closeMatch == null) {
|
||||
closeMatch = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Take this as a close match if there isn't one already
|
||||
if (closeMatch == null) {
|
||||
closeMatch = method;
|
||||
else if (matchInfo.isMatchRequiringConversion()) {
|
||||
if (matchRequiringConversion != null) {
|
||||
multipleOptions = true;
|
||||
}
|
||||
matchRequiringConversion = method;
|
||||
}
|
||||
}
|
||||
else if (matchInfo.isMatchRequiringConversion()) {
|
||||
if (matchRequiringConversion != null) {
|
||||
multipleOptions = true;
|
||||
}
|
||||
matchRequiringConversion = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (closeMatch != 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.
|
||||
@@ -154,12 +154,9 @@ final class LogAdapter {
|
||||
private static final LoggerContext loggerContext =
|
||||
LogManager.getContext(Log4jLog.class.getClassLoader(), false);
|
||||
|
||||
private final String name;
|
||||
|
||||
private final transient ExtendedLogger logger;
|
||||
private final ExtendedLogger logger;
|
||||
|
||||
public Log4jLog(String name) {
|
||||
this.name = name;
|
||||
LoggerContext context = loggerContext;
|
||||
if (context == null) {
|
||||
// Circular call in early-init scenario -> static field not initialized yet
|
||||
@@ -273,10 +270,6 @@ final class LogAdapter {
|
||||
this.logger.logIfEnabled(FQCN, level, null, message, exception);
|
||||
}
|
||||
}
|
||||
|
||||
protected Object readResolve() {
|
||||
return new Log4jLog(this.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -406,11 +406,8 @@ public class BeanPropertyRowMapper<T> implements RowMapper<T> {
|
||||
|
||||
/**
|
||||
* Retrieve a JDBC object value for the specified column.
|
||||
* <p>The default implementation calls
|
||||
* {@link JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class)}
|
||||
* using the type of the specified {@link PropertyDescriptor}.
|
||||
* <p>Subclasses may override this to check specific value types upfront,
|
||||
* or to post-process values returned from {@code getResultSetValue}.
|
||||
* <p>The default implementation delegates to
|
||||
* {@link #getColumnValue(ResultSet, int, Class)}.
|
||||
* @param rs is the ResultSet holding the data
|
||||
* @param index is the column index
|
||||
* @param pd the bean property that each result object is expected to match
|
||||
@@ -427,8 +424,8 @@ public class BeanPropertyRowMapper<T> implements RowMapper<T> {
|
||||
* Retrieve a JDBC object value for the specified column.
|
||||
* <p>The default implementation calls
|
||||
* {@link JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class)}.
|
||||
* <p>Subclasses may override this to check specific value types upfront,
|
||||
* or to post-process values returned from {@code getResultSetValue}.
|
||||
* Subclasses may override this to check specific value types upfront,
|
||||
* or to post-process values return from {@code getResultSetValue}.
|
||||
* @param rs is the ResultSet holding the data
|
||||
* @param index is the column index
|
||||
* @param paramType the target parameter type
|
||||
|
||||
@@ -60,7 +60,7 @@ import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* <b>This is the central delegate in the JDBC core package.</b>
|
||||
* <b>This is the central class in the JDBC core package.</b>
|
||||
* It simplifies the use of JDBC and helps to avoid common errors.
|
||||
* It executes core JDBC workflow, leaving application code to provide SQL
|
||||
* and extract results. This class executes SQL queries or updates, initiating
|
||||
@@ -417,7 +417,9 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
logger.debug("Executing SQL statement [" + sql + "]");
|
||||
}
|
||||
|
||||
// Callback to execute the statement.
|
||||
/**
|
||||
* Callback to execute the statement.
|
||||
*/
|
||||
class ExecuteStatementCallback implements StatementCallback<Object>, SqlProvider {
|
||||
@Override
|
||||
@Nullable
|
||||
|
||||
+10
-9
@@ -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.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -114,28 +115,28 @@ public class CallMetaDataContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a limited set of the {@code in} parameters to be used.
|
||||
* Specify a limited set of in parameters to be used.
|
||||
*/
|
||||
public void setLimitedInParameterNames(Set<String> limitedInParameterNames) {
|
||||
this.limitedInParameterNames = limitedInParameterNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the limited set of the {@code in} parameters to be used.
|
||||
* Get a limited set of in parameters to be used.
|
||||
*/
|
||||
public Set<String> getLimitedInParameterNames() {
|
||||
return this.limitedInParameterNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the names of the {@code out} parameters.
|
||||
* Specify the names of the out parameters.
|
||||
*/
|
||||
public void setOutParameterNames(List<String> outParameterNames) {
|
||||
this.outParameterNames = outParameterNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of the {@code out} parameter names.
|
||||
* Get a list of the out parameter names.
|
||||
*/
|
||||
public List<String> getOutParameterNames() {
|
||||
return this.outParameterNames;
|
||||
@@ -433,14 +434,14 @@ public class CallMetaDataContext {
|
||||
if (paramNameToUse == null) {
|
||||
paramNameToUse = "";
|
||||
}
|
||||
if (meta.isOutParameter()) {
|
||||
if (meta.getParameterType() == DatabaseMetaData.procedureColumnOut) {
|
||||
workParams.add(provider.createDefaultOutParameter(paramNameToUse, meta));
|
||||
outParamNames.add(paramNameToUse);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added meta-data out parameter for '" + paramNameToUse + "'");
|
||||
}
|
||||
}
|
||||
else if (meta.isInOutParameter()) {
|
||||
else if (meta.getParameterType() == DatabaseMetaData.procedureColumnInOut) {
|
||||
workParams.add(provider.createDefaultInOutParameter(paramNameToUse, meta));
|
||||
outParamNames.add(paramNameToUse);
|
||||
if (logger.isDebugEnabled()) {
|
||||
@@ -553,7 +554,7 @@ public class CallMetaDataContext {
|
||||
Map<String, String> callParameterNames = CollectionUtils.newHashMap(this.callParameters.size());
|
||||
for (SqlParameter parameter : this.callParameters) {
|
||||
if (parameter.isInputValueProvided()) {
|
||||
String parameterName = parameter.getName();
|
||||
String parameterName = parameter.getName();
|
||||
String parameterNameToMatch = provider.parameterNameToUse(parameterName);
|
||||
if (parameterNameToMatch != null) {
|
||||
callParameterNames.put(parameterNameToMatch.toLowerCase(), parameterName);
|
||||
@@ -605,7 +606,7 @@ public class CallMetaDataContext {
|
||||
int i = 0;
|
||||
for (SqlParameter parameter : this.callParameters) {
|
||||
if (parameter.isInputValueProvided()) {
|
||||
String parameterName = parameter.getName();
|
||||
String parameterName = parameter.getName();
|
||||
matchedParameters.put(parameterName, parameterValues[i++]);
|
||||
}
|
||||
}
|
||||
|
||||
+20
-20
@@ -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.
|
||||
@@ -43,7 +43,7 @@ public interface CallMetaDataProvider {
|
||||
|
||||
/**
|
||||
* Initialize the database specific management of procedure column meta-data.
|
||||
* <p>This is only called for databases that are supported. This initialization
|
||||
* This is only called for databases that are supported. This initialization
|
||||
* can be turned off by specifying that column meta-data should not be used.
|
||||
* @param databaseMetaData used to retrieve database specific information
|
||||
* @param catalogName name of catalog to use (or {@code null} if none)
|
||||
@@ -55,36 +55,30 @@ public interface CallMetaDataProvider {
|
||||
void initializeWithProcedureColumnMetaData(DatabaseMetaData databaseMetaData, @Nullable String catalogName,
|
||||
@Nullable String schemaName, @Nullable String procedureName) throws SQLException;
|
||||
|
||||
/**
|
||||
* Get the call parameter meta-data that is currently used.
|
||||
* @return a List of {@link CallParameterMetaData}
|
||||
*/
|
||||
List<CallParameterMetaData> getCallParameterMetaData();
|
||||
|
||||
/**
|
||||
* Provide any modification of the procedure name passed in to match the meta-data currently used.
|
||||
* <p>This could include altering the case.
|
||||
* This could include altering the case.
|
||||
*/
|
||||
@Nullable
|
||||
String procedureNameToUse(@Nullable String procedureName);
|
||||
|
||||
/**
|
||||
* Provide any modification of the catalog name passed in to match the meta-data currently used.
|
||||
* <p>This could include altering the case.
|
||||
* This could include altering the case.
|
||||
*/
|
||||
@Nullable
|
||||
String catalogNameToUse(@Nullable String catalogName);
|
||||
|
||||
/**
|
||||
* Provide any modification of the schema name passed in to match the meta-data currently used.
|
||||
* <p>This could include altering the case.
|
||||
* This could include altering the case.
|
||||
*/
|
||||
@Nullable
|
||||
String schemaNameToUse(@Nullable String schemaName);
|
||||
|
||||
/**
|
||||
* Provide any modification of the catalog name passed in to match the meta-data currently used.
|
||||
* <p>The returned value will be used for meta-data lookups. This could include altering the case
|
||||
* The returned value will be used for meta-data lookups. This could include altering the case
|
||||
* used or providing a base catalog if none is provided.
|
||||
*/
|
||||
@Nullable
|
||||
@@ -92,7 +86,7 @@ public interface CallMetaDataProvider {
|
||||
|
||||
/**
|
||||
* Provide any modification of the schema name passed in to match the meta-data currently used.
|
||||
* <p>The returned value will be used for meta-data lookups. This could include altering the case
|
||||
* The returned value will be used for meta-data lookups. This could include altering the case
|
||||
* used or providing a base schema if none is provided.
|
||||
*/
|
||||
@Nullable
|
||||
@@ -100,7 +94,7 @@ public interface CallMetaDataProvider {
|
||||
|
||||
/**
|
||||
* Provide any modification of the column name passed in to match the meta-data currently used.
|
||||
* <p>This could include altering the case.
|
||||
* This could include altering the case.
|
||||
* @param parameterName name of the parameter of column
|
||||
*/
|
||||
@Nullable
|
||||
@@ -108,7 +102,7 @@ public interface CallMetaDataProvider {
|
||||
|
||||
/**
|
||||
* Create a default out parameter based on the provided meta-data.
|
||||
* <p>This is used when no explicit parameter declaration has been made.
|
||||
* This is used when no explicit parameter declaration has been made.
|
||||
* @param parameterName the name of the parameter
|
||||
* @param meta meta-data used for this call
|
||||
* @return the configured SqlOutParameter
|
||||
@@ -117,7 +111,7 @@ public interface CallMetaDataProvider {
|
||||
|
||||
/**
|
||||
* Create a default in/out parameter based on the provided meta-data.
|
||||
* <p>This is used when no explicit parameter declaration has been made.
|
||||
* This is used when no explicit parameter declaration has been made.
|
||||
* @param parameterName the name of the parameter
|
||||
* @param meta meta-data used for this call
|
||||
* @return the configured SqlInOutParameter
|
||||
@@ -126,7 +120,7 @@ public interface CallMetaDataProvider {
|
||||
|
||||
/**
|
||||
* Create a default in parameter based on the provided meta-data.
|
||||
* <p>This is used when no explicit parameter declaration has been made.
|
||||
* This is used when no explicit parameter declaration has been made.
|
||||
* @param parameterName the name of the parameter
|
||||
* @param meta meta-data used for this call
|
||||
* @return the configured SqlParameter
|
||||
@@ -148,7 +142,7 @@ public interface CallMetaDataProvider {
|
||||
|
||||
/**
|
||||
* Does this database support returning ResultSets as ref cursors to be retrieved with
|
||||
* {@link java.sql.CallableStatement#getObject(int)} for the specified column?
|
||||
* {@link java.sql.CallableStatement#getObject(int)} for the specified column.
|
||||
*/
|
||||
boolean isRefCursorSupported();
|
||||
|
||||
@@ -164,12 +158,18 @@ public interface CallMetaDataProvider {
|
||||
boolean isProcedureColumnMetaDataUsed();
|
||||
|
||||
/**
|
||||
* Should we bypass the return parameter with the specified name?
|
||||
* <p>This allows the database specific implementation to skip the processing
|
||||
* Should we bypass the return parameter with the specified name.
|
||||
* This allows the database specific implementation to skip the processing
|
||||
* for specific results returned by the database call.
|
||||
*/
|
||||
boolean byPassReturnParameter(String parameterName);
|
||||
|
||||
/**
|
||||
* Get the call parameter meta-data that is currently used.
|
||||
* @return a List of {@link CallParameterMetaData}
|
||||
*/
|
||||
List<CallParameterMetaData> getCallParameterMetaData();
|
||||
|
||||
/**
|
||||
* Does the database support the use of catalog name in procedure calls?
|
||||
*/
|
||||
|
||||
+1
-23
@@ -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.
|
||||
@@ -107,28 +107,6 @@ public class CallParameterMetaData {
|
||||
this.parameterType == DatabaseMetaData.procedureColumnResult));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the declared parameter qualifies as an 'out' parameter
|
||||
* for our purposes: type {@link DatabaseMetaData#procedureColumnOut},
|
||||
* or in case of a function, {@link DatabaseMetaData#functionColumnOut}.
|
||||
* @since 5.3.31
|
||||
*/
|
||||
public boolean isOutParameter() {
|
||||
return (this.function ? this.parameterType == DatabaseMetaData.functionColumnOut :
|
||||
this.parameterType == DatabaseMetaData.procedureColumnOut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the declared parameter qualifies as an 'in-out' parameter
|
||||
* for our purposes: type {@link DatabaseMetaData#procedureColumnInOut},
|
||||
* or in case of a function, {@link DatabaseMetaData#functionColumnInOut}.
|
||||
* @since 5.3.31
|
||||
*/
|
||||
public boolean isInOutParameter() {
|
||||
return (this.function ? this.parameterType == DatabaseMetaData.functionColumnInOut :
|
||||
this.parameterType == DatabaseMetaData.procedureColumnInOut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parameter SQL type.
|
||||
*/
|
||||
|
||||
+56
-29
@@ -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,8 +35,7 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A generic implementation of the {@link CallMetaDataProvider} interface.
|
||||
*
|
||||
* <p>This class can be extended to provide database specific behavior.
|
||||
* This class can be extended to provide database specific behavior.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
@@ -114,7 +113,7 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
|
||||
@Nullable String schemaName, @Nullable String procedureName) throws SQLException {
|
||||
|
||||
this.procedureColumnMetaDataUsed = true;
|
||||
processProcedureColumns(databaseMetaData, catalogName, schemaName, procedureName);
|
||||
processProcedureColumns(databaseMetaData, catalogName, schemaName, procedureName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,19 +124,52 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
|
||||
@Override
|
||||
@Nullable
|
||||
public String procedureNameToUse(@Nullable String procedureName) {
|
||||
return identifierNameToUse(procedureName);
|
||||
if (procedureName == null) {
|
||||
return null;
|
||||
}
|
||||
else if (isStoresUpperCaseIdentifiers()) {
|
||||
return procedureName.toUpperCase();
|
||||
}
|
||||
else if (isStoresLowerCaseIdentifiers()) {
|
||||
return procedureName.toLowerCase();
|
||||
}
|
||||
else {
|
||||
return procedureName;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String catalogNameToUse(@Nullable String catalogName) {
|
||||
return identifierNameToUse(catalogName);
|
||||
if (catalogName == null) {
|
||||
return null;
|
||||
}
|
||||
else if (isStoresUpperCaseIdentifiers()) {
|
||||
return catalogName.toUpperCase();
|
||||
}
|
||||
else if (isStoresLowerCaseIdentifiers()) {
|
||||
return catalogName.toLowerCase();
|
||||
}
|
||||
else {
|
||||
return catalogName;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String schemaNameToUse(@Nullable String schemaName) {
|
||||
return identifierNameToUse(schemaName);
|
||||
if (schemaName == null) {
|
||||
return null;
|
||||
}
|
||||
else if (isStoresUpperCaseIdentifiers()) {
|
||||
return schemaName.toUpperCase();
|
||||
}
|
||||
else if (isStoresLowerCaseIdentifiers()) {
|
||||
return schemaName.toLowerCase();
|
||||
}
|
||||
else {
|
||||
return schemaName;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -165,7 +197,23 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
|
||||
@Override
|
||||
@Nullable
|
||||
public String parameterNameToUse(@Nullable String parameterName) {
|
||||
return identifierNameToUse(parameterName);
|
||||
if (parameterName == null) {
|
||||
return null;
|
||||
}
|
||||
else if (isStoresUpperCaseIdentifiers()) {
|
||||
return parameterName.toUpperCase();
|
||||
}
|
||||
else if (isStoresLowerCaseIdentifiers()) {
|
||||
return parameterName.toLowerCase();
|
||||
}
|
||||
else {
|
||||
return parameterName;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean byPassReturnParameter(String parameterName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -208,11 +256,6 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
|
||||
return this.procedureColumnMetaDataUsed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean byPassReturnParameter(String parameterName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify whether the database supports the use of catalog name in procedure calls.
|
||||
@@ -273,22 +316,6 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private String identifierNameToUse(@Nullable String identifierName) {
|
||||
if (identifierName == null) {
|
||||
return null;
|
||||
}
|
||||
else if (isStoresUpperCaseIdentifiers()) {
|
||||
return identifierName.toUpperCase();
|
||||
}
|
||||
else if (isStoresLowerCaseIdentifiers()) {
|
||||
return identifierName.toLowerCase();
|
||||
}
|
||||
else {
|
||||
return identifierName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the procedure column meta-data.
|
||||
*/
|
||||
|
||||
+12
-12
@@ -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.
|
||||
@@ -526,6 +526,17 @@ public interface NamedParameterJdbcOperations {
|
||||
int update(String sql, SqlParameterSource paramSource, KeyHolder generatedKeyHolder, String[] keyColumnNames)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Executes a batch using the supplied SQL statement with the batch of supplied arguments.
|
||||
* @param sql the SQL statement to execute
|
||||
* @param batchValues the array of Maps containing the batch of arguments for the query
|
||||
* @return an array containing the numbers of rows affected by each update in the batch
|
||||
* (may also contain special JDBC-defined negative values for affected rows such as
|
||||
* {@link java.sql.Statement#SUCCESS_NO_INFO}/{@link java.sql.Statement#EXECUTE_FAILED})
|
||||
* @throws DataAccessException if there is any problem issuing the update
|
||||
*/
|
||||
int[] batchUpdate(String sql, Map<String, ?>[] batchValues);
|
||||
|
||||
/**
|
||||
* Execute a batch using the supplied SQL statement with the batch of supplied arguments.
|
||||
* @param sql the SQL statement to execute
|
||||
@@ -538,15 +549,4 @@ public interface NamedParameterJdbcOperations {
|
||||
*/
|
||||
int[] batchUpdate(String sql, SqlParameterSource[] batchArgs);
|
||||
|
||||
/**
|
||||
* Executes a batch using the supplied SQL statement with the batch of supplied arguments.
|
||||
* @param sql the SQL statement to execute
|
||||
* @param batchValues the array of Maps containing the batch of arguments for the query
|
||||
* @return an array containing the numbers of rows affected by each update in the batch
|
||||
* (may also contain special JDBC-defined negative values for affected rows such as
|
||||
* {@link java.sql.Statement#SUCCESS_NO_INFO}/{@link java.sql.Statement#EXECUTE_FAILED})
|
||||
* @throws DataAccessException if there is any problem issuing the update
|
||||
*/
|
||||
int[] batchUpdate(String sql, Map<String, ?>[] batchValues);
|
||||
|
||||
}
|
||||
|
||||
+5
-6
@@ -359,6 +359,11 @@ public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations
|
||||
return getJdbcOperations().update(psc, generatedKeyHolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] batchUpdate(String sql, Map<String, ?>[] batchValues) {
|
||||
return batchUpdate(sql, SqlParameterSourceUtils.createBatch(batchValues));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] batchUpdate(String sql, SqlParameterSource[] batchArgs) {
|
||||
if (batchArgs.length == 0) {
|
||||
@@ -383,11 +388,6 @@ public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] batchUpdate(String sql, Map<String, ?>[] batchValues) {
|
||||
return batchUpdate(sql, SqlParameterSourceUtils.createBatch(batchValues));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build a {@link PreparedStatementCreator} based on the given SQL and named parameters.
|
||||
@@ -436,7 +436,6 @@ public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations
|
||||
* @return a representation of the parsed SQL statement
|
||||
*/
|
||||
protected ParsedSql getParsedSql(String sql) {
|
||||
Assert.notNull(sql, "SQL must not be null");
|
||||
return this.parsedSqlCache.get(sql);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -45,8 +45,8 @@ import org.springframework.util.Assert;
|
||||
* lobCreator.setBlobAsBinaryStream(ps, 2, contentStream, contentLength);
|
||||
* lobCreator.setClobAsString(ps, 3, description);
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
* }
|
||||
* );</pre>
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.0.2
|
||||
|
||||
+8
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -41,13 +41,13 @@ import org.springframework.lang.Nullable;
|
||||
* final LobHandler lobHandler = new DefaultLobHandler(); // reusable object
|
||||
*
|
||||
* jdbcTemplate.query(
|
||||
* "SELECT content FROM imagedb WHERE image_name=?", new Object[] {name},
|
||||
* new AbstractLobStreamingResultSetExtractor() {
|
||||
* public void streamData(ResultSet rs) throws SQLException, IOException {
|
||||
* FileCopyUtils.copy(lobHandler.getBlobAsBinaryStream(rs, 1), contentStream);
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
* "SELECT content FROM imagedb WHERE image_name=?", new Object[] {name},
|
||||
* new AbstractLobStreamingResultSetExtractor() {
|
||||
* public void streamData(ResultSet rs) throws SQLException, IOException {
|
||||
* FileCopyUtils.copy(lobHandler.getBlobAsBinaryStream(rs, 1), contentStream);
|
||||
* }
|
||||
* }
|
||||
* );</pre>
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.0.2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -209,7 +209,7 @@ public class SqlLobValue implements DisposableSqlTypeValue {
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the LobCreator.
|
||||
* Close the LobCreator, if any.
|
||||
*/
|
||||
@Override
|
||||
public void cleanup() {
|
||||
|
||||
+15
-5
@@ -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.
|
||||
@@ -75,10 +75,10 @@ public abstract class AbstractDataSource implements DataSource {
|
||||
throw new UnsupportedOperationException("setLogWriter");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() {
|
||||
return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of JDBC 4.0's Wrapper interface
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -95,4 +95,14 @@ public abstract class AbstractDataSource implements DataSource {
|
||||
return iface.isInstance(this);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of JDBC 4.1's getParentLogger method
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() {
|
||||
return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+23
-13
@@ -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.
|
||||
@@ -104,16 +104,6 @@ public class DelegatingDataSource implements DataSource, InitializingBean {
|
||||
return obtainTargetDataSource().getConnection(username, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoginTimeout() throws SQLException {
|
||||
return obtainTargetDataSource().getLoginTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoginTimeout(int seconds) throws SQLException {
|
||||
obtainTargetDataSource().setLoginTimeout(seconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter getLogWriter() throws SQLException {
|
||||
return obtainTargetDataSource().getLogWriter();
|
||||
@@ -125,10 +115,20 @@ public class DelegatingDataSource implements DataSource, InitializingBean {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() {
|
||||
return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
|
||||
public int getLoginTimeout() throws SQLException {
|
||||
return obtainTargetDataSource().getLoginTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoginTimeout(int seconds) throws SQLException {
|
||||
obtainTargetDataSource().setLoginTimeout(seconds);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of JDBC 4.0's Wrapper interface
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
@@ -143,4 +143,14 @@ public class DelegatingDataSource implements DataSource, InitializingBean {
|
||||
return (iface.isInstance(this) || obtainTargetDataSource().isWrapperFor(iface));
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of JDBC 4.1's getParentLogger method
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() {
|
||||
return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -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.
|
||||
@@ -186,7 +186,7 @@ public class TransactionAwareDataSourceProxy extends DelegatingDataSource {
|
||||
// Allow for differentiating between the proxy and the raw Connection.
|
||||
StringBuilder sb = new StringBuilder("Transaction-aware proxy for target Connection ");
|
||||
if (this.target != null) {
|
||||
sb.append('[').append(this.target).append(']');
|
||||
sb.append('[').append(this.target.toString()).append(']');
|
||||
}
|
||||
else {
|
||||
sb.append(" from DataSource [").append(this.targetDataSource).append(']');
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -61,7 +61,7 @@ public abstract class AbstractRoutingDataSource extends AbstractDataSource imple
|
||||
|
||||
/**
|
||||
* Specify the map of target DataSources, with the lookup key as key.
|
||||
* <p>The mapped value can either be a corresponding {@link javax.sql.DataSource}
|
||||
* The mapped value can either be a corresponding {@link javax.sql.DataSource}
|
||||
* instance or a data source name String (to be resolved via a
|
||||
* {@link #setDataSourceLookup DataSourceLookup}).
|
||||
* <p>The key can be of arbitrary type; this class implements the
|
||||
@@ -213,7 +213,6 @@ public abstract class AbstractRoutingDataSource extends AbstractDataSource imple
|
||||
return (iface.isInstance(this) || determineTargetDataSource().isWrapperFor(iface));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the current target DataSource. Determines the
|
||||
* {@link #determineCurrentLookupKey() current lookup key}, performs
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2008 the original author 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,9 @@ import org.springframework.jdbc.support.SqlValue;
|
||||
|
||||
/**
|
||||
* Subinterface of {@link org.springframework.jdbc.support.SqlValue}
|
||||
* that specifically indicates passing in XML data to a specified column.
|
||||
* that supports passing in XML data to specified column and adds a
|
||||
* cleanup callback, to be invoked after the value has been set and
|
||||
* the corresponding statement has been executed.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5.5
|
||||
|
||||
+3
-26
@@ -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.
|
||||
@@ -304,8 +304,8 @@ public abstract class AbstractAdaptableMessageListener
|
||||
* @see #setMessageConverter
|
||||
*/
|
||||
protected Message buildMessage(Session session, Object result) throws JMSException {
|
||||
Object content = preProcessResponse(result instanceof JmsResponse ?
|
||||
((JmsResponse<?>) result).getResponse() : result);
|
||||
Object content = preProcessResponse(result instanceof JmsResponse
|
||||
? ((JmsResponse<?>) result).getResponse() : result);
|
||||
|
||||
MessageConverter converter = getMessageConverter();
|
||||
if (converter != null) {
|
||||
@@ -553,29 +553,6 @@ public abstract class AbstractAdaptableMessageListener
|
||||
}
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(getClass().getSimpleName());
|
||||
if (this.payload == null) {
|
||||
sb.append(" [rawMessage=").append(this.message);
|
||||
}
|
||||
else {
|
||||
sb.append(" [payload=");
|
||||
if (this.payload instanceof byte[]) {
|
||||
sb.append("byte[").append(((byte[]) this.payload).length).append(']');
|
||||
}
|
||||
else {
|
||||
sb.append(this.payload);
|
||||
}
|
||||
}
|
||||
if (this.headers != null) {
|
||||
sb.append(", headers=").append(this.headers);
|
||||
}
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-41
@@ -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.
|
||||
@@ -40,7 +40,6 @@ import org.springframework.jms.support.QosSettings;
|
||||
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
|
||||
import org.springframework.jms.support.converter.MessageConverter;
|
||||
import org.springframework.jms.support.converter.MessageType;
|
||||
import org.springframework.jms.support.converter.MessagingMessageConverter;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.converter.MessageConversionException;
|
||||
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;
|
||||
@@ -341,45 +340,6 @@ public class MessagingMessageListenerAdapterTests {
|
||||
return responseMessage;
|
||||
}
|
||||
|
||||
@Test
|
||||
void lazyResolutionMessageToStringProvidesBestEffortWithUnresolvedPayload() throws JMSException {
|
||||
MessagingMessageListenerAdapter adapter = getSimpleInstance("echo", Message.class);
|
||||
MessagingMessageConverter messagingMessageConverter = adapter.getMessagingMessageConverter();
|
||||
assertThat(messagingMessageConverter).isNotNull();
|
||||
TextMessage message = new StubTextMessage();
|
||||
assertThat(messagingMessageConverter.fromMessage(message)).isInstanceOfSatisfying(Message.class, msg ->
|
||||
assertThat(msg.toString()).contains("rawMessage=").contains(message.toString())
|
||||
.doesNotContain("payload=").doesNotContain("headers="));
|
||||
}
|
||||
|
||||
@Test
|
||||
void lazyResolutionMessageToStringWithResolvedPayload() throws JMSException {
|
||||
MessagingMessageListenerAdapter adapter = getSimpleInstance("echo", Message.class);
|
||||
MessagingMessageConverter messagingMessageConverter = adapter.getMessagingMessageConverter();
|
||||
assertThat(messagingMessageConverter).isNotNull();
|
||||
TextMessage message = new StubTextMessage("Hello");
|
||||
assertThat(messagingMessageConverter.fromMessage(message)).isInstanceOfSatisfying(Message.class, msg -> {
|
||||
msg.getPayload(); // force resolution
|
||||
assertThat(msg.toString()).contains("payload=Hello")
|
||||
.doesNotContain("rawMessage=").doesNotContain("headers=");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void lazyResolutionMessageToStringWithResolvedPayloadAndHeaders() throws JMSException {
|
||||
MessagingMessageListenerAdapter adapter = getSimpleInstance("echo", Message.class);
|
||||
MessagingMessageConverter messagingMessageConverter = adapter.getMessagingMessageConverter();
|
||||
assertThat(messagingMessageConverter).isNotNull();
|
||||
TextMessage message = new StubTextMessage("Hello");
|
||||
message.setJMSPriority(7);
|
||||
assertThat(messagingMessageConverter.fromMessage(message)).isInstanceOfSatisfying(Message.class, msg -> {
|
||||
msg.getPayload();
|
||||
msg.getHeaders(); // force resolution
|
||||
assertThat(msg.toString()).contains("payload=Hello").contains("headers=").contains("jms_priority=7")
|
||||
.doesNotContain("rawMessage=");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
protected MessagingMessageListenerAdapter getSimpleInstance(String methodName, Class<?>... parameterTypes) {
|
||||
Method m = ReflectionUtils.findMethod(SampleBean.class, methodName, parameterTypes);
|
||||
|
||||
-4
@@ -281,10 +281,6 @@ class ChannelSendOperator<T> extends Mono<Void> implements Scannable {
|
||||
return;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (this.state == State.READY_TO_WRITE) {
|
||||
s.request(n);
|
||||
return;
|
||||
}
|
||||
if (this.writeSubscriber != null) {
|
||||
if (this.state == State.EMITTING_CACHED_SIGNALS) {
|
||||
this.demandBeforeReadyToWrite = n;
|
||||
|
||||
+1
-1
@@ -200,7 +200,7 @@ public final class MessageBuilder<T> {
|
||||
* @since 4.1
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Message<T> createMessage(T payload, MessageHeaders messageHeaders) {
|
||||
public static <T> Message<T> createMessage(@Nullable T payload, MessageHeaders messageHeaders) {
|
||||
Assert.notNull(payload, "Payload must not be null");
|
||||
Assert.notNull(messageHeaders, "MessageHeaders must not be null");
|
||||
if (payload instanceof Throwable) {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -96,7 +96,7 @@ public class HibernateExceptionTranslator implements PersistenceExceptionTransla
|
||||
DataAccessException dae = this.jdbcExceptionTranslator.translate(
|
||||
"Hibernate operation: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
|
||||
if (dae != null) {
|
||||
return dae;
|
||||
throw dae;
|
||||
}
|
||||
}
|
||||
return SessionFactoryUtils.convertHibernateAccessException(ex);
|
||||
|
||||
+2
@@ -777,6 +777,8 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
/**
|
||||
* Convert the given HibernateException to an appropriate exception
|
||||
* from the {@code org.springframework.dao} hierarchy.
|
||||
* <p>Will automatically apply a specified SQLExceptionTranslator to a
|
||||
* Hibernate JDBCException, else rely on Hibernate's default translation.
|
||||
* @param ex the HibernateException that occurred
|
||||
* @return a corresponding DataAccessException
|
||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
||||
|
||||
+1
-2
@@ -77,7 +77,7 @@ public abstract class SharedEntityManagerCreator {
|
||||
|
||||
private static final Set<String> transactionRequiringMethods = new HashSet<>(6);
|
||||
|
||||
private static final Set<String> queryTerminatingMethods = new HashSet<>(10);
|
||||
private static final Set<String> queryTerminatingMethods = new HashSet<>(9);
|
||||
|
||||
static {
|
||||
transactionRequiringMethods.add("joinTransaction");
|
||||
@@ -93,7 +93,6 @@ public abstract class SharedEntityManagerCreator {
|
||||
queryTerminatingMethods.add("getResultStream"); // javax.persistence.Query.getResultStream()
|
||||
queryTerminatingMethods.add("getResultList"); // javax.persistence.Query.getResultList()
|
||||
queryTerminatingMethods.add("list"); // org.hibernate.query.Query.list()
|
||||
queryTerminatingMethods.add("scroll"); // org.hibernate.query.Query.scroll()
|
||||
queryTerminatingMethods.add("stream"); // org.hibernate.query.Query.stream()
|
||||
queryTerminatingMethods.add("uniqueResult"); // org.hibernate.query.Query.uniqueResult()
|
||||
queryTerminatingMethods.add("uniqueResultOptional"); // org.hibernate.query.Query.uniqueResultOptional()
|
||||
|
||||
+3
-3
@@ -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.
|
||||
@@ -124,8 +124,8 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
||||
* @since 5.1
|
||||
* @see java.sql.SQLException
|
||||
* @see org.hibernate.JDBCException
|
||||
* @see org.springframework.jdbc.support.SQLExceptionSubclassTranslator
|
||||
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
|
||||
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
|
||||
*/
|
||||
public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
|
||||
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
|
||||
@@ -247,7 +247,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
||||
DataAccessException dae = this.jdbcExceptionTranslator.translate(
|
||||
"Hibernate operation: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
|
||||
if (dae != null) {
|
||||
return dae;
|
||||
throw dae;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user