Compare commits

..

1 Commits

Author SHA1 Message Date
Spring Builds 2aeddb4fcb Release v5.3.25 2023-01-11 11:05:48 +00:00
210 changed files with 1970 additions and 4299 deletions
+1 -4
View File
@@ -28,7 +28,6 @@ buildSrc/build
/integration-tests/build
/src/asciidoc/build
target/
/target/
# Eclipse artifacts, including WTP generated manifests
.classpath
@@ -46,6 +45,4 @@ atlassian-ide-plugin.xml
.gradletasknamecache
# VS Code
.vscode/
cached-antora-playbook.yml
.vscode/
+1 -1
View File
@@ -1,3 +1,3 @@
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=8.0.372-librca
java=8.0.352-librca
+16 -16
View File
@@ -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.93.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.33"
mavenBom "io.netty:netty-bom:4.1.86.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.27"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR13"
mavenBom "io.rsocket:rsocket-bom:1.1.3"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.51.v20230217"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.50.v20221201"
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.20.0') {
dependencySet(group: 'org.apache.logging.log4j', version: '2.19.0') {
entry 'log4j-api'
entry 'log4j-core'
entry 'log4j-jul'
@@ -92,7 +92,7 @@ configure(allprojects) { project ->
entry 'jibx-run'
}
dependency "org.ogce:xpp3:1.1.6"
dependency "org.yaml:snakeyaml:1.33"
dependency "org.yaml:snakeyaml:1.30"
dependency "com.h2database:h2:2.1.214"
dependency "com.github.ben-manes.caffeine:caffeine:2.9.3"
@@ -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.75') {
dependencySet(group: 'org.apache.tomcat', version: '9.0.70') {
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.75') {
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.70') {
entry 'tomcat-embed-core'
entry 'tomcat-embed-websocket'
}
dependencySet(group: 'io.undertow', version: '2.2.24.Final') {
dependencySet(group: 'io.undertow', version: '2.2.22.Final') {
entry 'undertow-core'
entry('undertow-servlet') {
exclude group: "org.jboss.spec.javax.servlet", name: "jboss-servlet-api_4.0_spec"
@@ -191,7 +191,7 @@ configure(allprojects) { project ->
dependency "org.junit.support:testng-engine:1.0.4"
dependency "org.hamcrest:hamcrest:2.2"
dependency "org.awaitility:awaitility:3.1.6"
dependency "org.assertj:assertj-core:3.24.2"
dependency "org.assertj:assertj-core:3.24.1"
dependencySet(group: 'org.xmlunit', version: '2.9.0') {
entry 'xmlunit-assertj'
entry('xmlunit-matchers') {
@@ -206,10 +206,10 @@ configure(allprojects) { project ->
}
dependency "io.mockk:mockk:1.12.1"
dependency("net.sourceforge.htmlunit:htmlunit:2.70.0") {
dependency("net.sourceforge.htmlunit:htmlunit:2.69.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:htmlunit-driver:2.70.0") {
dependency("org.seleniumhq.selenium:htmlunit-driver:2.67.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
@@ -238,7 +238,7 @@ configure(allprojects) { project ->
dependency "com.ibm.websphere:uow:6.0.2.17"
dependency "com.jamonapi:jamon:2.82"
dependency "joda-time:joda-time:2.10.13"
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.12"
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.10"
dependency "org.javamoney:moneta:1.3"
dependency "com.sun.activation:javax.activation:1.2.0"
@@ -340,7 +340,7 @@ configure([rootProject] + javaProjects) { project ->
}
checkstyle {
toolVersion = "10.9.3"
toolVersion = "10.6.0"
configDirectory.set(rootProject.file("src/checkstyle"))
}
@@ -377,9 +377,9 @@ configure([rootProject] + javaProjects) { project ->
"https://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
"https://www.ehcache.org/apidocs/2.10.4/",
"https://www.quartz-scheduler.org/api/2.3.0/",
"https://www.javadoc.io/doc/com.fasterxml.jackson.core/jackson-core/2.12.7/",
"https://www.javadoc.io/doc/com.fasterxml.jackson.core/jackson-databind/2.12.7/",
"https://www.javadoc.io/doc/com.fasterxml.jackson.dataformat/jackson-dataformat-xml/2.12.7/",
"https://fasterxml.github.io/jackson-core/javadoc/2.10/",
"https://fasterxml.github.io/jackson-databind/javadoc/2.10/",
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.10/",
"https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/",
"https://projectreactor.io/docs/test/release/api/",
"https://junit.org/junit4/javadoc/4.13.2/",
+2 -2
View File
@@ -3,10 +3,10 @@ set -e
case "$1" in
java8)
echo "https://github.com/bell-sw/Liberica/releases/download/8u372+7/bellsoft-jdk8u372+7-linux-amd64.tar.gz"
echo "https://github.com/bell-sw/Liberica/releases/download/8u345+1/bellsoft-jdk8u345+1-linux-amd64.tar.gz"
;;
java17)
echo "https://github.com/bell-sw/Liberica/releases/download/17.0.7+7/bellsoft-jdk17.0.7+7-linux-amd64.tar.gz"
echo "https://github.com/bell-sw/Liberica/releases/download/17.0.4+8/bellsoft-jdk17.0.4+8-linux-amd64.tar.gz"
;;
*)
echo $"Unknown java version"
+3
View File
@@ -8,4 +8,7 @@ milestone: "5.3.x"
build-name: "spring-framework"
pipeline-name: "spring-framework"
concourse-url: "https://ci.spring.io"
registry-mirror-host: docker.repo.spring.io
registry-mirror-username: ((artifactory-username))
registry-mirror-password: ((artifactory-password))
task-timeout: 1h00m
+55 -10
View File
@@ -23,6 +23,11 @@ anchors:
docker-resource-source: &docker-resource-source
username: ((docker-hub-username))
password: ((docker-hub-password))
tag: ((milestone))
registry-mirror-vars: &registry-mirror-vars
registry-mirror-host: ((registry-mirror-host))
registry-mirror-username: ((registry-mirror-username))
registry-mirror-password: ((registry-mirror-password))
slack-fail-params: &slack-fail-params
text: >
:concourse-failed: <https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}|${BUILD_PIPELINE_NAME} ${BUILD_JOB_NAME} failed!>
@@ -43,31 +48,31 @@ resource_types:
- name: registry-image
type: registry-image
source:
<<: *docker-resource-source
repository: concourse/registry-image-resource
tag: 1.7.1
tag: 1.5.0
- name: artifactory-resource
type: registry-image
source:
<<: *docker-resource-source
repository: springio/artifactory-resource
tag: 0.0.18
tag: 0.0.17
- name: github-release
type: registry-image
source:
<<: *docker-resource-source
repository: concourse/github-release-resource
tag: 1.8.0
tag: 1.5.5
- name: github-status-resource
type: registry-image
source:
<<: *docker-resource-source
repository: dpb587/github-status-resource
tag: master
- name: pull-request
type: registry-image
source:
repository: teliaoss/github-pr-resource
tag: v0.23.0
- name: slack-notification
type: registry-image
source:
<<: *docker-resource-source
repository: cfcommunity/slack-notification-resource
tag: latest
resources:
@@ -96,7 +101,6 @@ resources:
source:
<<: *docker-resource-source
repository: ((docker-hub-organization))/spring-framework-ci
tag: ((milestone))
- name: artifactory-repo
type: artifactory-resource
icon: package-variant
@@ -105,6 +109,14 @@ resources:
username: ((artifactory-username))
password: ((artifactory-password))
build_name: ((build-name))
- name: git-pull-request
type: pull-request
icon: source-pull
source:
access_token: ((github-ci-pull-request-token))
repository: ((github-repo-name))
base_branch: ((branch))
ignore_paths: ["ci/*"]
- name: repo-status-build
type: github-status-resource
icon: eye-check-outline
@@ -156,7 +168,7 @@ jobs:
image: ci-image
vars:
ci-image-name: ci-image
<<: *docker-resource-source
<<: *registry-mirror-vars
- put: ci-image
params:
image: ci-image/image.tar
@@ -245,6 +257,37 @@ jobs:
<<: *slack-fail-params
- put: repo-status-jdk17-build
params: { state: "success", commit: "git-repo" }
- name: build-pull-requests
serial: true
public: true
plan:
- get: ci-image
- get: git-repo
resource: git-pull-request
trigger: true
version: every
- do:
- put: git-pull-request
params:
path: git-repo
status: pending
- task: build-pr
image: ci-image
file: git-repo/ci/tasks/build-pr.yml
privileged: true
timeout: ((task-timeout))
params:
BRANCH: ((branch))
on_success:
put: git-pull-request
params:
path: git-repo
status: success
on_failure:
put: git-pull-request
params:
path: git-repo
status: failure
- name: stage-milestone
serial: true
plan:
@@ -397,3 +440,5 @@ groups:
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release"]
- name: "ci-images"
jobs: ["build-ci-images"]
- name: "pull-requests"
jobs: [ "build-pull-requests" ]
+5 -3
View File
@@ -4,9 +4,11 @@ image_resource:
type: registry-image
source:
repository: concourse/oci-build-task
tag: 0.10.0
username: ((docker-hub-username))
password: ((docker-hub-password))
tag: 0.9.1
registry_mirror:
host: ((registry-mirror-host))
username: ((registry-mirror-username))
password: ((registry-mirror-password))
inputs:
- name: ci-images-git-repo
outputs:
+1 -1
View File
@@ -1,4 +1,4 @@
version=5.3.28
version=5.3.25
org.gradle.jvmargs=-Xmx2048m
org.gradle.caching=true
org.gradle.parallel=true
+4 -3
View File
@@ -3,7 +3,7 @@ configurations {
}
dependencies {
asciidoctorExt("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.6.1")
asciidoctorExt("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.5.0")
}
repositories {
@@ -73,8 +73,9 @@ pluginManager.withPlugin("kotlin") {
}
task downloadResources(type: Download) {
src "https://repo.spring.io/artifactory/snapshot/io/spring/docresources/" +
"spring-doc-resources/0.2.6-SNAPSHOT/spring-doc-resources-0.2.6-20210308.231804-2.zip"
def version = "0.2.5"
src "https://repo.spring.io/release/io/spring/docresources/" +
"spring-doc-resources/$version/spring-doc-resources-${version}.zip"
dest project.file("$buildDir/docs/spring-doc-resources.zip")
onlyIfModified true
useETag "all"
+2 -2
View File
@@ -7,8 +7,8 @@ pluginManagement {
}
plugins {
id "com.gradle.enterprise" version "3.12.1"
id "io.spring.ge.conventions" version "0.0.13"
id "com.gradle.enterprise" version "3.11.1"
id "io.spring.ge.conventions" version "0.0.11"
}
include "spring-aop"
@@ -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.
@@ -38,14 +38,6 @@ import org.springframework.util.StringUtils;
* for an advice method from the pointcut expression, returning, and throwing clauses.
* If an unambiguous interpretation is not available, it returns {@code null}.
*
* <h3>Algorithm Summary</h3>
* <p>If an unambiguous binding can be deduced, then it is.
* If the advice requirements cannot possibly be satisfied, then {@code null}
* is returned. By setting the {@link #setRaiseExceptions(boolean) raiseExceptions}
* property to {@code true}, descriptive exceptions will be thrown instead of
* returning {@code null} in the case that the parameter names cannot be discovered.
*
* <h3>Algorithm Details</h3>
* <p>This class interprets arguments in the following way:
* <ol>
* <li>If the first parameter of the method is of type {@link JoinPoint}
@@ -73,15 +65,15 @@ import org.springframework.util.StringUtils;
* zero we proceed to the next stage. If {@code a} &gt; 1 then an
* {@code AmbiguousBindingException} is raised. If {@code a} == 1,
* and there are no unbound arguments of type {@code Annotation+},
* then an {@code IllegalArgumentException} is raised. If there is
* then an {@code IllegalArgumentException} is raised. if there is
* exactly one such argument, then the corresponding parameter name is
* assigned the value from the pointcut expression.</li>
* <li>If a {@code returningName} has been set, and there are no unbound arguments
* <li>If a returningName has been set, and there are no unbound arguments
* then an {@code IllegalArgumentException} is raised. If there is
* more than one unbound argument then an
* {@code AmbiguousBindingException} is raised. If there is exactly
* one unbound argument then the corresponding parameter name is assigned
* the value of the {@code returningName}.</li>
* the value &lt;returningName&gt;.</li>
* <li>If there remain unbound arguments, then the pointcut expression is
* examined once more for {@code this}, {@code target}, and
* {@code args} pointcut expressions used in the binding form (binding
@@ -107,12 +99,20 @@ import org.springframework.util.StringUtils;
* <p>The behavior on raising an {@code IllegalArgumentException} or
* {@code AmbiguousBindingException} is configurable to allow this discoverer
* to be used as part of a chain-of-responsibility. By default the condition will
* be logged and the {@link #getParameterNames(Method)} method will simply return
* be logged and the {@code getParameterNames(..)} method will simply return
* {@code null}. If the {@link #setRaiseExceptions(boolean) raiseExceptions}
* property is set to {@code true}, the conditions will be thrown as
* {@code IllegalArgumentException} and {@code AmbiguousBindingException},
* respectively.
*
* <p>Was that perfectly clear? ;)
*
* <p>Short version: If an unambiguous binding can be deduced, then it is.
* If the advice requirements cannot possibly be satisfied, then {@code null}
* is returned. By setting the {@link #setRaiseExceptions(boolean) raiseExceptions}
* property to {@code true}, descriptive exceptions will be thrown instead of
* returning {@code null} in the case that the parameter names cannot be discovered.
*
* @author Adrian Colyer
* @author Juergen Hoeller
* @since 2.0
@@ -158,7 +158,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
/** The pointcut expression associated with the advice, as a simple String. */
@Nullable
private final String pointcutExpression;
private String pointcutExpression;
private boolean raiseExceptions;
@@ -197,7 +197,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
/**
* If {@code afterReturning} advice binds the return value, the
* {@code returning} variable name must be specified.
* returning variable name must be specified.
* @param returningName the name of the returning variable
*/
public void setReturningName(@Nullable String returningName) {
@@ -206,17 +206,18 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
/**
* If {@code afterThrowing} advice binds the thrown value, the
* {@code throwing} variable name must be specified.
* throwing variable name must be specified.
* @param throwingName the name of the throwing variable
*/
public void setThrowingName(@Nullable String throwingName) {
this.throwingName = throwingName;
}
/**
* Deduce the parameter names for an advice method.
* <p>See the {@link AspectJAdviceParameterNameDiscoverer class-level javadoc}
* for this class for details on the algorithm used.
* <p>See the {@link AspectJAdviceParameterNameDiscoverer class level javadoc}
* for this class for details of the algorithm used.
* @param method the target {@link Method}
* @return the parameter names
*/
@@ -315,13 +316,13 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
private void bindParameterName(int index, @Nullable String name) {
private void bindParameterName(int index, String name) {
this.parameterNameBindings[index] = name;
this.numberOfRemainingUnboundArguments--;
}
/**
* If the first parameter is of type JoinPoint or ProceedingJoinPoint, bind "thisJoinPoint" as
* If the first parameter is of type JoinPoint or ProceedingJoinPoint,bind "thisJoinPoint" as
* parameter name and return true, else return false.
*/
private boolean maybeBindThisJoinPoint() {
@@ -366,8 +367,8 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
if (throwableIndex == -1) {
throw new IllegalStateException("Binding of throwing parameter '" + this.throwingName +
"' could not be completed as no available arguments are a subtype of Throwable");
throw new IllegalStateException("Binding of throwing parameter '" + this.throwingName
+ "' could not be completed as no available arguments are a subtype of Throwable");
}
else {
bindParameterName(throwableIndex, this.throwingName);
@@ -399,6 +400,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
}
/**
* Parse the string pointcut expression looking for:
* &#64;this, &#64;target, &#64;args, &#64;within, &#64;withincode, &#64;annotation.
@@ -463,7 +465,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
}
/**
/*
* If the token starts meets Java identifier conventions, it's in.
*/
@Nullable
@@ -531,6 +533,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
}
if (varNames.size() > 1) {
throw new AmbiguousBindingException("Found " + varNames.size() +
" candidate this(), target() or args() variables but only one unbound argument slot");
@@ -606,7 +609,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
// else varNames.size must be 0 and we have nothing to bind.
}
/**
/*
* We've found the start of a binding pointcut at the given index into the
* token array. Now we need to extract the pointcut body and return it.
*/
@@ -706,7 +709,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
return false;
}
/**
/*
* Return {@code true} if the given argument type is a subclass
* of the given supertype.
*/
@@ -734,7 +737,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
return count;
}
/**
/*
* Find the argument index with the given type, and bind the given
* {@code varName} in that position.
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +23,10 @@ import org.springframework.lang.Nullable;
* Subinterface of {@link org.springframework.aop.aspectj.AspectInstanceFactory}
* that returns {@link AspectMetadata} associated with AspectJ-annotated classes.
*
* <p>Ideally, AspectInstanceFactory would include this method itself, but because
* AspectMetadata uses Java-5-only {@link org.aspectj.lang.reflect.AjType},
* we need to split out this subinterface.
*
* @author Rod Johnson
* @since 2.0
* @see AspectMetadata
@@ -31,13 +35,13 @@ import org.springframework.lang.Nullable;
public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactory {
/**
* Get the AspectJ AspectMetadata for this factory's aspect.
* Return the AspectJ AspectMetadata for this factory's aspect.
* @return the aspect metadata
*/
AspectMetadata getAspectMetadata();
/**
* Get the best possible creation mutex for this factory.
* Return the best possible creation mutex for this factory.
* @return the mutex object (may be {@code null} for no mutex to use)
* @since 4.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.
@@ -521,7 +521,6 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
copy.copyFrom(this);
copy.targetSource = EmptyTargetSource.forClass(getTargetClass(), getTargetSource().isStatic());
copy.advisorChainFactory = this.advisorChainFactory;
copy.methodCache = this.methodCache;
copy.interfaces = new ArrayList<>(this.interfaces);
copy.advisors = new ArrayList<>(this.advisors);
return copy;
@@ -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.
@@ -283,8 +283,8 @@ class CglibAopProxy implements AopProxy, Serializable {
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Parameters used for optimization choices...
boolean isFrozen = this.advised.isFrozen();
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
// Choose an "aop" interceptor (used for AOP calls).
@@ -899,9 +899,9 @@ class CglibAopProxy implements AopProxy, Serializable {
// Proxy is not yet available, but that shouldn't matter.
List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
boolean haveAdvice = !chain.isEmpty();
boolean isFrozen = this.advised.isFrozen();
boolean exposeProxy = this.advised.isExposeProxy();
boolean isStatic = this.advised.getTargetSource().isStatic();
boolean isFrozen = this.advised.isFrozen();
if (haveAdvice || !isFrozen) {
// If exposing the proxy, then AOP_PROXY must be used.
if (exposeProxy) {
@@ -970,9 +970,6 @@ class CglibAopProxy implements AopProxy, Serializable {
if (this.advised.isExposeProxy() != otherAdvised.isExposeProxy()) {
return false;
}
if (this.advised.isOpaque() != otherAdvised.isOpaque()) {
return false;
}
if (this.advised.getTargetSource().isStatic() != otherAdvised.getTargetSource().isStatic()) {
return false;
}
@@ -1019,6 +1016,10 @@ class CglibAopProxy implements AopProxy, Serializable {
Advice advice = advisor.getAdvice();
hashCode = 13 * hashCode + advice.getClass().hashCode();
}
hashCode = 13 * hashCode + (this.advised.isFrozen() ? 1 : 0);
hashCode = 13 * hashCode + (this.advised.isExposeProxy() ? 1 : 0);
hashCode = 13 * hashCode + (this.advised.isOptimize() ? 1 : 0);
hashCode = 13 * hashCode + (this.advised.isOpaque() ? 1 : 0);
return hashCode;
}
}
@@ -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.
@@ -123,33 +123,7 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
return Proxy.newProxyInstance(determineClassLoader(classLoader), this.proxiedInterfaces, this);
}
/**
* Determine whether the JDK bootstrap or platform loader has been suggested ->
* use higher-level loader which can see Spring infrastructure classes instead.
*/
private ClassLoader determineClassLoader(@Nullable ClassLoader classLoader) {
if (classLoader == null) {
// JDK bootstrap loader -> use spring-aop ClassLoader instead.
return getClass().getClassLoader();
}
if (classLoader.getParent() == null) {
// Potentially the JDK platform loader on JDK 9+
ClassLoader aopClassLoader = getClass().getClassLoader();
ClassLoader aopParent = aopClassLoader.getParent();
while (aopParent != null) {
if (classLoader == aopParent) {
// Suggested ClassLoader is ancestor of spring-aop ClassLoader
// -> use spring-aop ClassLoader itself instead.
return aopClassLoader;
}
aopParent = aopParent.getParent();
}
}
// Regular case: use suggested ClassLoader as-is.
return classLoader;
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
/**
@@ -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.
@@ -34,7 +34,6 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Convenient superclass for
@@ -82,11 +81,6 @@ public abstract class AbstractBeanFactoryBasedTargetSourceCreator
return this.beanFactory;
}
private ConfigurableBeanFactory getConfigurableBeanFactory() {
Assert.state(this.beanFactory != null, "BeanFactory not set");
return this.beanFactory;
}
//---------------------------------------------------------------------
// Implementation of the TargetSourceCreator interface
@@ -110,7 +104,7 @@ public abstract class AbstractBeanFactoryBasedTargetSourceCreator
// We need to override just this bean definition, as it may reference other beans
// and we're happy to take the parent's definition for those.
// Always use prototype scope if demanded.
BeanDefinition bd = getConfigurableBeanFactory().getMergedBeanDefinition(beanName);
BeanDefinition bd = this.beanFactory.getMergedBeanDefinition(beanName);
GenericBeanDefinition bdCopy = new GenericBeanDefinition(bd);
if (isPrototypeBased()) {
bdCopy.setScope(BeanDefinition.SCOPE_PROTOTYPE);
@@ -132,7 +126,7 @@ public abstract class AbstractBeanFactoryBasedTargetSourceCreator
protected DefaultListableBeanFactory getInternalBeanFactoryForBean(String beanName) {
synchronized (this.internalBeanFactories) {
return this.internalBeanFactories.computeIfAbsent(beanName,
name -> buildInternalBeanFactory(getConfigurableBeanFactory()));
name -> buildInternalBeanFactory(this.beanFactory));
}
}
@@ -1,10 +0,0 @@
/**
* Various {@link org.springframework.aop.framework.autoproxy.TargetSourceCreator}
* implementations for use with Spring's AOP auto-proxying support.
*/
@NonNullApi
@NonNullFields
package org.springframework.aop.framework.autoproxy.target;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
@@ -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.
@@ -24,8 +24,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.aop.TargetSource;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
@@ -59,18 +57,15 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
protected final Log logger = LogFactory.getLog(getClass());
/** Name of the target bean we will create on each invocation. */
@Nullable
private String targetBeanName;
/** Class of the target. */
@Nullable
private volatile Class<?> targetClass;
/**
* BeanFactory that owns this TargetSource. We need to hold onto this
* reference so that we can create new prototype instances as necessary.
*/
@Nullable
private BeanFactory beanFactory;
@@ -91,7 +86,6 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
* Return the name of the target bean in the factory.
*/
public String getTargetBeanName() {
Assert.state(this.targetBeanName != null, "Target bean name not set");
return this.targetBeanName;
}
@@ -121,13 +115,11 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
* Return the owning BeanFactory.
*/
public BeanFactory getBeanFactory() {
Assert.state(this.beanFactory != null, "BeanFactory not set");
return this.beanFactory;
}
@Override
@Nullable
public Class<?> getTargetClass() {
Class<?> targetClass = this.targetClass;
if (targetClass != null) {
@@ -136,7 +128,7 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
synchronized (this) {
// Full check within synchronization, entering the BeanFactory interaction algorithm only once...
targetClass = this.targetClass;
if (targetClass == null && this.beanFactory != null && this.targetBeanName != null) {
if (targetClass == null && this.beanFactory != null) {
// Determine type of the target bean.
targetClass = this.beanFactory.getType(this.targetBeanName);
if (targetClass == null) {
@@ -190,16 +182,18 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
@Override
public int hashCode() {
return getClass().hashCode() * 13 + ObjectUtils.nullSafeHashCode(this.targetBeanName);
int hashCode = getClass().hashCode();
hashCode = 13 * hashCode + ObjectUtils.nullSafeHashCode(this.beanFactory);
hashCode = 13 * hashCode + ObjectUtils.nullSafeHashCode(this.targetBeanName);
return hashCode;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(getClass().getSimpleName());
sb.append(" for target bean '").append(this.targetBeanName).append('\'');
Class<?> targetClass = this.targetClass;
if (targetClass != null) {
sb.append(" of type [").append(targetClass.getName()).append(']');
if (this.targetClass != null) {
sb.append(" of type [").append(this.targetClass.getName()).append(']');
}
return sb.toString();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,7 +46,6 @@ public abstract class AbstractLazyCreationTargetSource implements TargetSource {
protected final Log logger = LogFactory.getLog(getClass());
/** The lazily initialized target object. */
@Nullable
private Object lazyTarget;
@@ -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.
@@ -70,7 +70,6 @@ public final class EmptyTargetSource implements TargetSource, Serializable {
// Instance implementation
//---------------------------------------------------------------------
@Nullable
private final Class<?> targetClass;
private final boolean isStatic;
@@ -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.
@@ -95,7 +95,8 @@ public class HotSwappableTargetSource implements TargetSource, Serializable {
/**
* Two HotSwappableTargetSources are equal if the current target objects are equal.
* Two HotSwappableTargetSources are equal if the current target
* objects are equal.
*/
@Override
public boolean equals(Object other) {
@@ -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.
@@ -82,8 +82,14 @@ public class SingletonTargetSource implements TargetSource, Serializable {
*/
@Override
public boolean equals(Object other) {
return (this == other || (other instanceof SingletonTargetSource &&
this.target.equals(((SingletonTargetSource) other).target)));
if (this == other) {
return true;
}
if (!(other instanceof SingletonTargetSource)) {
return false;
}
SingletonTargetSource otherTargetSource = (SingletonTargetSource) other;
return this.target.equals(otherTargetSource.target);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -58,12 +58,7 @@ public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
* is meant to be per thread per instance of the ThreadLocalTargetSource class.
*/
private final ThreadLocal<Object> targetInThread =
new NamedThreadLocal<Object>("Thread-local instance of bean") {
@Override
public String toString() {
return super.toString() + " '" + getTargetBeanName() + "'";
}
};
new NamedThreadLocal<>("Thread-local instance of bean '" + getTargetBeanName() + "'");
/**
* Set of managed targets, enabling us to keep track of the targets we've created.
@@ -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.
@@ -16,10 +16,7 @@
package org.springframework.aop.framework;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.accessibility.Accessible;
@@ -383,43 +380,6 @@ public class ProxyFactoryTests {
assertThat(proxy.getName()).isEqualTo("tb");
}
@Test
public void testCharSequenceProxy() {
CharSequence target = "test";
ProxyFactory pf = new ProxyFactory(target);
ClassLoader cl = target.getClass().getClassLoader();
CharSequence proxy = (CharSequence) pf.getProxy(cl);
assertThat(proxy.toString()).isEqualTo(target);
}
@Test
public void testDateProxy() {
Date target = new Date();
ProxyFactory pf = new ProxyFactory(target);
pf.setProxyTargetClass(true);
ClassLoader cl = target.getClass().getClassLoader();
Date proxy = (Date) pf.getProxy(cl);
assertThat(proxy.getTime()).isEqualTo(target.getTime());
}
@Test
public void testJdbcSavepointProxy() throws SQLException {
Savepoint target = new Savepoint() {
@Override
public int getSavepointId() throws SQLException {
return 1;
}
@Override
public String getSavepointName() throws SQLException {
return "sp";
}
};
ProxyFactory pf = new ProxyFactory(target);
ClassLoader cl = Savepoint.class.getClassLoader();
Savepoint proxy = (Savepoint) pf.getProxy(cl);
assertThat(proxy.getSavepointName()).isEqualTo("sp");
}
@Order(2)
public static class A implements Runnable {
@@ -431,7 +391,7 @@ public class ProxyFactoryTests {
@Order(1)
public static class B implements Runnable {
public static class B implements Runnable{
@Override
public void run() {
@@ -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.
@@ -247,8 +247,7 @@ public abstract class BeanUtils {
// A single public constructor
return (Constructor<T>) ctors[0];
}
else if (ctors.length == 0) {
// No public constructors -> check non-public
else if (ctors.length == 0){
ctors = clazz.getDeclaredConstructors();
if (ctors.length == 1) {
// A single non-public constructor, e.g. from a non-public record type
@@ -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.
@@ -136,10 +136,7 @@ public interface BeanFactory {
* <p>Translates aliases back to the corresponding canonical bean name.
* <p>Will ask the parent factory if the bean cannot be found in this factory instance.
* @param name the name of the bean to retrieve
* @return an instance of the bean.
* Note that the return value will never be {@code null} but possibly a stub for
* {@code null} returned from a factory method, to be checked via {@code equals(null)}.
* Consider using {@link #getBeanProvider(Class)} for resolving optional dependencies.
* @return an instance of the bean
* @throws NoSuchBeanDefinitionException if there is no bean with the specified name
* @throws BeansException if the bean could not be obtained
*/
@@ -155,11 +152,7 @@ public interface BeanFactory {
* <p>Will ask the parent factory if the bean cannot be found in this factory instance.
* @param name the name of the bean to retrieve
* @param requiredType type the bean must match; can be an interface or superclass
* @return an instance of the bean.
* Note that the return value will never be {@code null}. In case of a stub for
* {@code null} from a factory method having been resolved for the requested bean, a
* {@code BeanNotOfRequiredTypeException} against the NullBean stub will be raised.
* Consider using {@link #getBeanProvider(Class)} for resolving optional dependencies.
* @return an instance of the bean
* @throws NoSuchBeanDefinitionException if there is no such bean definition
* @throws BeanNotOfRequiredTypeException if the bean is not of the required type
* @throws BeansException if the bean could not be created
@@ -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.
@@ -665,7 +665,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
if (value != null || this.required) {
cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (value != null && autowiredBeanNames.size() == 1) {
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
@@ -778,7 +778,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
String autowiredBeanName = it.next();
if (arguments[i] != null && beanFactory.containsBean(autowiredBeanName) &&
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
descriptors[i], autowiredBeanName, paramTypes[i]);
@@ -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.
@@ -25,7 +25,6 @@ import java.util.Set;
import org.springframework.beans.SimpleTypeConverter;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.DependencyDescriptor;
@@ -241,11 +240,10 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
}
}
if (targetAnnotation == null) {
BeanFactory beanFactory = getBeanFactory();
// Look for matching annotation on the target class
if (beanFactory != null) {
if (getBeanFactory() != null) {
try {
Class<?> beanType = beanFactory.getType(bdHolder.getBeanName());
Class<?> beanType = getBeanFactory().getType(bdHolder.getBeanName());
if (beanType != null) {
targetAnnotation = AnnotationUtils.getAnnotation(ClassUtils.getUserClass(beanType), type);
}
@@ -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.
@@ -184,9 +184,8 @@ public abstract class YamlProcessor {
protected Yaml createYaml() {
LoaderOptions loaderOptions = new LoaderOptions();
loaderOptions.setAllowDuplicateKeys(false);
DumperOptions dumperOptions = new DumperOptions();
return new Yaml(new FilteringConstructor(loaderOptions), new Representer(dumperOptions),
dumperOptions, loaderOptions);
return new Yaml(new FilteringConstructor(loaderOptions), new Representer(),
new DumperOptions(), loaderOptions);
}
private boolean process(MatchCallback callback, Yaml yaml, Resource resource) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -102,7 +102,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
private boolean singletonsCurrentlyInDestruction = false;
/** Disposable bean instances: bean name to disposable instance. */
private final Map<String, DisposableBean> disposableBeans = new LinkedHashMap<>();
private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
/** Map between containing bean names: bean name to Set of bean names that the bean contains. */
private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);
@@ -340,7 +340,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
* (within the entire factory).
* @param beanName the name of the bean
*/
public boolean isSingletonCurrentlyInCreation(@Nullable String beanName) {
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
@@ -554,7 +554,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
// Destroy the corresponding DisposableBean instance.
DisposableBean disposableBean;
synchronized (this.disposableBeans) {
disposableBean = this.disposableBeans.remove(beanName);
disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
}
destroyBean(beanName, disposableBean);
}
@@ -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.
@@ -68,9 +68,9 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
private static final String SHUTDOWN_METHOD_NAME = "shutdown";
private static final Log logger = LogFactory.getLog(DisposableBeanAdapter.class);
private final Object bean;
private final String beanName;
@@ -214,15 +214,12 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
}
catch (Throwable ex) {
if (logger.isWarnEnabled()) {
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
// Log at warn level like below but add the exception stacktrace only with debug level
logger.warn(msg, ex);
}
else {
logger.warn(msg + ": " + ex);
}
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex);
}
else {
logger.warn(msg + ": " + ex);
}
}
}
@@ -243,15 +240,12 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
}
catch (Throwable ex) {
if (logger.isWarnEnabled()) {
String msg = "Invocation of close method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
// Log at warn level like below but add the exception stacktrace only with debug level
logger.warn(msg, ex);
}
else {
logger.warn(msg + ": " + ex);
}
String msg = "Invocation of close method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex);
}
else {
logger.warn(msg + ": " + ex);
}
}
}
@@ -326,23 +320,18 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
}
catch (InvocationTargetException ex) {
if (logger.isWarnEnabled()) {
String msg = "Custom destroy method '" + this.destroyMethodName + "' on bean with name '" +
this.beanName + "' threw an exception";
if (logger.isDebugEnabled()) {
// Log at warn level like below but add the exception stacktrace only with debug level
logger.warn(msg, ex.getTargetException());
}
else {
logger.warn(msg + ": " + ex.getTargetException());
}
String msg = "Custom destroy method '" + this.destroyMethodName + "' on bean with name '" +
this.beanName + "' threw an exception";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex.getTargetException());
}
else {
logger.warn(msg + ": " + ex.getTargetException());
}
}
catch (Throwable ex) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to invoke custom destroy method '" + this.destroyMethodName +
"' on bean with name '" + this.beanName + "'", ex);
}
logger.warn("Failed to invoke custom destroy method '" + this.destroyMethodName +
"' on bean with name '" + this.beanName + "'", ex);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -547,8 +547,7 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
* @see DefaultNamespaceHandlerResolver#DefaultNamespaceHandlerResolver(ClassLoader)
*/
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
ResourceLoader resourceLoader = getResourceLoader();
ClassLoader cl = (resourceLoader != null ? resourceLoader.getClassLoader() : getBeanClassLoader());
ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader());
return new DefaultNamespaceHandlerResolver(cl);
}
@@ -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.
@@ -395,7 +395,6 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
}
@SuppressWarnings("try")
public static class ActiveResource implements AutoCloseable {
public ActiveResource getResource() {
@@ -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.
@@ -436,6 +436,7 @@ class DefaultListableBeanFactoryTests {
@Test
void empty() {
ListableBeanFactory lbf = new DefaultListableBeanFactory();
assertThat(lbf.getBeanDefinitionNames() != null).as("No beans defined --> array != null").isTrue();
assertThat(lbf.getBeanDefinitionNames().length == 0).as("No beans defined after no arg constructor").isTrue();
assertThat(lbf.getBeanDefinitionCount() == 0).as("No beans defined after no arg constructor").isTrue();
@@ -777,6 +778,21 @@ class DefaultListableBeanFactoryTests {
assertThat(factory.getType("child")).isEqualTo(DerivedTestBean.class);
}
@Test
void nameAlreadyBound() {
Properties p = new Properties();
p.setProperty("kerry.(class)", TestBean.class.getName());
p.setProperty("kerry.age", "35");
registerBeanDefinitions(p);
try {
registerBeanDefinitions(p);
}
catch (BeanDefinitionStoreException ex) {
assertThat(ex.getBeanName()).isEqualTo("kerry");
// expected
}
}
private void singleTestBean(ListableBeanFactory lbf) {
assertThat(lbf.getBeanDefinitionCount() == 1).as("1 beans defined").isTrue();
String[] names = lbf.getBeanDefinitionNames();
@@ -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.
@@ -133,26 +133,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getTestBean2()).isSameAs(tb);
}
@Test
public void testResourceInjectionWithNullBean() {
RootBeanDefinition bd = new RootBeanDefinition(NonPublicResourceInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
RootBeanDefinition tb = new RootBeanDefinition(NullFactoryMethods.class);
tb.setFactoryMethodName("createTestBean");
bf.registerBeanDefinition("testBean", tb);
NonPublicResourceInjectionBean bean = (NonPublicResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
bean = (NonPublicResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
}
@Test
public void testExtendedResourceInjection() {
RootBeanDefinition bd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class);
@@ -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.
@@ -51,7 +51,6 @@ import org.springframework.util.ObjectUtils;
* @author Juergen Hoeller
* @author Stephane Nicoll
* @author Sam Brannen
* @author Brian Clozel
* @since 4.3
* @see CaffeineCache
*/
@@ -189,13 +188,8 @@ public class CaffeineCacheManager implements CacheManager {
@Override
@Nullable
public Cache getCache(String name) {
if (this.dynamic) {
Cache cache = this.cacheMap.get(name);
return (cache != null) ? cache : this.cacheMap.computeIfAbsent(name, this::createCaffeineCache);
}
else {
return this.cacheMap.get(name);
}
return this.cacheMap.computeIfAbsent(name, cacheName ->
this.dynamic ? createCaffeineCache(cacheName) : null);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -132,10 +132,10 @@ public class JavaMailSenderImpl implements JavaMailSender {
}
/**
* Allow {@code Map} access to the JavaMail properties of this sender,
* Allow {code Map} access to the JavaMail properties of this sender,
* with the option to add or override specific entries.
* <p>Useful for specifying entries directly, for example via
* {@code javaMailProperties[mail.smtp.auth]}.
* {code javaMailProperties[mail.smtp.auth]}.
*/
public Properties getJavaMailProperties() {
return this.javaMailProperties;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,7 +47,7 @@ public class NameMatchCacheOperationSource implements CacheOperationSource, Seri
/** Keys are method names; values are TransactionAttributes. */
private final Map<String, Collection<CacheOperation>> nameMap = new LinkedHashMap<>();
private Map<String, Collection<CacheOperation>> nameMap = new LinkedHashMap<>();
/**
@@ -117,8 +117,8 @@ public class NameMatchCacheOperationSource implements CacheOperationSource, Seri
if (!(other instanceof NameMatchCacheOperationSource)) {
return false;
}
NameMatchCacheOperationSource otherCos = (NameMatchCacheOperationSource) other;
return ObjectUtils.nullSafeEquals(this.nameMap, otherCos.nameMap);
NameMatchCacheOperationSource otherTas = (NameMatchCacheOperationSource) other;
return ObjectUtils.nullSafeEquals(this.nameMap, otherTas.nameMap);
}
@Override
@@ -130,5 +130,4 @@ public class NameMatchCacheOperationSource implements CacheOperationSource, Seri
public String toString() {
return getClass().getName() + ": " + this.nameMap;
}
}
@@ -274,7 +274,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
handleAsyncError(ex);
}
else if (event != null) {
publishEvents(event);
publishEvent(event);
}
});
}
@@ -468,9 +468,6 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
}
/**
* Inner class to avoid a hard dependency on the Reactive Streams API at runtime.
*/
private class ReactiveResultHandler {
public boolean subscribeToPublisher(Object result) {
@@ -484,9 +481,6 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
}
/**
* Reactive Streams Subscriber for publishing follow-up events.
*/
private class EventPublicationSubscriber implements Subscriber<Object> {
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -447,7 +447,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
@Override
public void setApplicationStartup(ApplicationStartup applicationStartup) {
Assert.notNull(applicationStartup, "ApplicationStartup must not be null");
Assert.notNull(applicationStartup, "applicationStartup should not be null");
this.applicationStartup = applicationStartup;
}
@@ -729,11 +729,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
/**
* Modify the application context's internal bean factory after its standard
* initialization. The initial definition resources will have been loaded but no
* post-processors will have run and no derived bean definitions will have been
* registered, and most importantly, no beans will have been instantiated yet.
* <p>This template method allows for registering special BeanPostProcessors
* etc in certain AbstractApplicationContext subclasses.
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for registering special
* BeanPostProcessors etc in certain ApplicationContext implementations.
* @param beanFactory the bean factory used by the application context
*/
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
@@ -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.
@@ -117,12 +117,9 @@ public @interface Scheduled {
* last invocation and the start of the next.
* <p>The time unit is milliseconds by default but can be overridden via
* {@link #timeUnit}.
* <p>This attribute variant supports Spring-style "${...}" placeholders
* as well as SpEL expressions.
* @return the delay as a String value &mdash; for example, a placeholder
* or a {@link java.time.Duration#parse java.time.Duration} compliant value
* @since 3.2.2
* @see #fixedDelay()
*/
String fixedDelayString() default "";
@@ -138,12 +135,9 @@ public @interface Scheduled {
* Execute the annotated method with a fixed period between invocations.
* <p>The time unit is milliseconds by default but can be overridden via
* {@link #timeUnit}.
* <p>This attribute variant supports Spring-style "${...}" placeholders
* as well as SpEL expressions.
* @return the period as a String value &mdash; for example, a placeholder
* or a {@link java.time.Duration#parse java.time.Duration} compliant value
* @since 3.2.2
* @see #fixedRate()
*/
String fixedRateString() default "";
@@ -162,12 +156,9 @@ public @interface Scheduled {
* {@link #fixedRate} or {@link #fixedDelay} task.
* <p>The time unit is milliseconds by default but can be overridden via
* {@link #timeUnit}.
* <p>This attribute variant supports Spring-style "${...}" placeholders
* as well as SpEL expressions.
* @return the initial delay as a String value &mdash; for example, a placeholder
* or a {@link java.time.Duration#parse java.time.Duration} compliant value
* @since 3.2.2
* @see #initialDelay()
*/
String initialDelayString() default "";
@@ -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.
@@ -83,9 +83,6 @@ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, Sche
private TaskExecutorAdapter adaptedExecutor;
@Nullable
private TaskDecorator taskDecorator;
/**
* Create a new ConcurrentTaskExecutor, using a single thread executor as default.
@@ -141,7 +138,6 @@ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, Sche
* @since 4.3
*/
public final void setTaskDecorator(TaskDecorator taskDecorator) {
this.taskDecorator = taskDecorator;
this.adaptedExecutor.setTaskDecorator(taskDecorator);
}
@@ -178,15 +174,11 @@ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, Sche
}
private TaskExecutorAdapter getAdaptedExecutor(Executor concurrentExecutor) {
private static TaskExecutorAdapter getAdaptedExecutor(Executor concurrentExecutor) {
if (managedExecutorServiceClass != null && managedExecutorServiceClass.isInstance(concurrentExecutor)) {
return new ManagedTaskExecutorAdapter(concurrentExecutor);
}
TaskExecutorAdapter adapter = new TaskExecutorAdapter(concurrentExecutor);
if (this.taskDecorator != null) {
adapter.setTaskDecorator(this.taskDecorator);
}
return adapter;
return new TaskExecutorAdapter(concurrentExecutor);
}
@@ -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.
@@ -100,7 +100,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
*/
public ConcurrentTaskScheduler() {
super();
initScheduledExecutor(null);
this.scheduledExecutor = initScheduledExecutor(null);
}
/**
@@ -115,7 +115,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
*/
public ConcurrentTaskScheduler(ScheduledExecutorService scheduledExecutor) {
super(scheduledExecutor);
initScheduledExecutor(scheduledExecutor);
this.scheduledExecutor = initScheduledExecutor(scheduledExecutor);
}
/**
@@ -131,11 +131,11 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
*/
public ConcurrentTaskScheduler(Executor concurrentExecutor, ScheduledExecutorService scheduledExecutor) {
super(concurrentExecutor);
initScheduledExecutor(scheduledExecutor);
this.scheduledExecutor = initScheduledExecutor(scheduledExecutor);
}
private void initScheduledExecutor(@Nullable ScheduledExecutorService scheduledExecutor) {
private ScheduledExecutorService initScheduledExecutor(@Nullable ScheduledExecutorService scheduledExecutor) {
if (scheduledExecutor != null) {
this.scheduledExecutor = scheduledExecutor;
this.enterpriseConcurrentScheduler = (managedScheduledExecutorServiceClass != null &&
@@ -145,6 +145,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
this.scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
this.enterpriseConcurrentScheduler = false;
}
return this.scheduledExecutor;
}
/**
@@ -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.
@@ -36,10 +36,7 @@ import org.springframework.lang.Nullable;
* Base class for setting up a {@link java.util.concurrent.ExecutorService}
* (typically a {@link java.util.concurrent.ThreadPoolExecutor} or
* {@link java.util.concurrent.ScheduledThreadPoolExecutor}).
*
* <p>Defines common configuration settings and common lifecycle handling,
* inheriting thread customization options (name, priority, etc) from
* {@link org.springframework.util.CustomizableThreadCreator}.
* Defines common configuration settings and common lifecycle handling.
*
* @author Juergen Hoeller
* @since 3.0
@@ -202,7 +199,8 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
/**
* Calls {@code shutdown} when the BeanFactory destroys the executor instance.
* Calls {@code shutdown} when the BeanFactory destroys
* the task executor instance.
* @see #shutdown()
*/
@Override
@@ -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.
@@ -125,7 +125,7 @@ public class FieldError extends ObjectError {
@Override
public String toString() {
return "Field error in object '" + getObjectName() + "' on field '" + this.field +
"': rejected value [" + ObjectUtils.nullSafeConciseToString(this.rejectedValue) + "]; " +
"': rejected value [" + ObjectUtils.nullSafeToString(this.rejectedValue) + "]; " +
resolvableToString();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,6 @@ import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.aop.testfixture.advice.CountingBeforeAdvice;
import org.springframework.aop.testfixture.interceptor.NopInterceptor;
import org.springframework.beans.testfixture.beans.ITestBean;
@@ -36,8 +35,6 @@ import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -90,7 +87,8 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
AdvisedSupport pc = new AdvisedSupport(ITestBean.class);
pc.addAdvice(new NopInterceptor());
AopProxy aop = createAopProxy(pc);
assertThatExceptionOfType(AopConfigException.class).isThrownBy(aop::getProxy);
assertThatExceptionOfType(AopConfigException.class).isThrownBy(
aop::getProxy);
}
@Test
@@ -138,8 +136,8 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
Object proxy = aop.getProxy();
assertThat(AopUtils.isCglibProxy(proxy)).isTrue();
assertThat(proxy).isInstanceOf(ITestBean.class);
assertThat(proxy).isInstanceOf(TestBean.class);
assertThat(proxy instanceof ITestBean).isTrue();
assertThat(proxy instanceof TestBean).isTrue();
TestBean tb = (TestBean) proxy;
assertThat(tb.getAge()).isEqualTo(32);
@@ -306,8 +304,6 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
CglibAopProxy cglib = new CglibAopProxy(as);
ITestBean proxy1 = (ITestBean) cglib.getProxy();
ITestBean proxy1a = (ITestBean) cglib.getProxy();
assertThat(proxy1a.getClass()).isSameAs(proxy1.getClass());
mockTargetSource.setTarget(proxy1);
as = new AdvisedSupport(new Class<?>[]{});
@@ -316,40 +312,7 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
cglib = new CglibAopProxy(as);
ITestBean proxy2 = (ITestBean) cglib.getProxy();
assertThat(proxy2).isInstanceOf(Serializable.class);
assertThat(proxy2.getClass()).isNotSameAs(proxy1.getClass());
ITestBean proxy2a = (ITestBean) cglib.getProxy();
assertThat(proxy2a).isInstanceOf(Serializable.class);
assertThat(proxy2a.getClass()).isSameAs(proxy2.getClass());
mockTargetSource.setTarget(proxy1);
as = new AdvisedSupport(new Class<?>[]{});
as.setTargetSource(mockTargetSource);
as.addAdvisor(new DefaultPointcutAdvisor(new AnnotationMatchingPointcut(Nullable.class), new NopInterceptor()));
cglib = new CglibAopProxy(as);
ITestBean proxy3 = (ITestBean) cglib.getProxy();
assertThat(proxy3).isInstanceOf(Serializable.class);
assertThat(proxy3.getClass()).isNotSameAs(proxy2.getClass());
ITestBean proxy3a = (ITestBean) cglib.getProxy();
assertThat(proxy3a).isInstanceOf(Serializable.class);
assertThat(proxy3a.getClass()).isSameAs(proxy3.getClass());
mockTargetSource.setTarget(proxy1);
as = new AdvisedSupport(new Class<?>[]{});
as.setTargetSource(mockTargetSource);
as.addAdvisor(new DefaultPointcutAdvisor(new AnnotationMatchingPointcut(NonNull.class), new NopInterceptor()));
cglib = new CglibAopProxy(as);
ITestBean proxy4 = (ITestBean) cglib.getProxy();
assertThat(proxy4).isInstanceOf(Serializable.class);
assertThat(proxy4.getClass()).isNotSameAs(proxy3.getClass());
ITestBean proxy4a = (ITestBean) cglib.getProxy();
assertThat(proxy4a).isInstanceOf(Serializable.class);
assertThat(proxy4a.getClass()).isSameAs(proxy4.getClass());
assertThat(proxy2 instanceof Serializable).isTrue();
}
@Test
@@ -368,7 +331,7 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
proxy.doTest();
}
catch (Exception ex) {
assertThat(ex).as("Invalid exception class").isInstanceOf(ApplicationContextException.class);
assertThat(ex instanceof ApplicationContextException).as("Invalid exception class").isTrue();
}
assertThat(proxy.isCatchInvoked()).as("Catch was not invoked").isTrue();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,7 +41,6 @@ class ImportTests {
private DefaultListableBeanFactory processConfigurationClasses(Class<?>... classes) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.setAllowBeanDefinitionOverriding(false);
for (Class<?> clazz : classes) {
beanFactory.registerBeanDefinition(clazz.getSimpleName(), new RootBeanDefinition(clazz));
}
@@ -57,9 +56,8 @@ class ImportTests {
for (Class<?> clazz : classes) {
beanFactory.getBean(clazz);
}
}
// ------------------------------------------------------------------------
}
@Test
void testProcessImportsWithAsm() {
@@ -160,13 +158,6 @@ class ImportTests {
assertBeanDefinitionCount(configClasses + beansInClasses, FirstLevel.class);
}
@Test
void testImportAnnotationWithThreeLevelRecursionAndDoubleImport() {
int configClasses = 5;
int beansInClasses = 5;
assertBeanDefinitionCount(configClasses + beansInClasses, FirstLevel.class, FirstLevelPlus.class);
}
// ------------------------------------------------------------------------
@Test
@@ -176,6 +167,7 @@ class ImportTests {
assertBeanDefinitionCount((configClasses + beansInClasses), WithMultipleArgumentsToImportAnnotation.class);
}
@Test
void testImportAnnotationWithMultipleArgumentsResultingInOverriddenBeanDefinition() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
@@ -253,11 +245,6 @@ class ImportTests {
}
}
@Configuration
@Import(ThirdLevel.class)
static class FirstLevelPlus {
}
@Configuration
@Import({ThirdLevel.class, InitBean.class})
static class SecondLevel {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -133,7 +133,7 @@ public class DateFormattingTests {
assertThat(exception)
.hasMessageContaining("for property 'styleDate'")
.hasCauseInstanceOf(ConversionFailedException.class).cause()
.hasMessageContaining("for value [99/01/01]")
.hasMessageContaining("for value '99/01/01'")
.hasCauseInstanceOf(IllegalArgumentException.class).cause()
.hasMessageContaining("Parse attempt failed for value [99/01/01]")
.hasCauseInstanceOf(ParseException.class).cause()
@@ -353,7 +353,7 @@ public class DateFormattingTests {
assertThat(fieldError.unwrap(TypeMismatchException.class))
.hasMessageContaining("for property 'patternDateWithFallbackPatterns'")
.hasCauseInstanceOf(ConversionFailedException.class).cause()
.hasMessageContaining("for value [210302]")
.hasMessageContaining("for value '210302'")
.hasCauseInstanceOf(IllegalArgumentException.class).cause()
.hasMessageContaining("Parse attempt failed for value [210302]")
.hasCauseInstanceOf(ParseException.class).cause()
@@ -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.
@@ -333,7 +333,7 @@ class DateTimeFormattingTests {
assertThat(fieldError.unwrap(TypeMismatchException.class))
.hasMessageContaining("for property 'isoLocalDate'")
.hasCauseInstanceOf(ConversionFailedException.class).cause()
.hasMessageContaining("for value [2009-31-10]")
.hasMessageContaining("for value '2009-31-10'")
.hasCauseInstanceOf(IllegalArgumentException.class).cause()
.hasMessageContaining("Parse attempt failed for value [2009-31-10]")
.hasCauseInstanceOf(DateTimeParseException.class).cause()
@@ -540,7 +540,7 @@ class DateTimeFormattingTests {
assertThat(fieldError.unwrap(TypeMismatchException.class))
.hasMessageContaining("for property 'patternLocalDateWithFallbackPatterns'")
.hasCauseInstanceOf(ConversionFailedException.class).cause()
.hasMessageContaining("for value [210302]")
.hasMessageContaining("for value '210302'")
.hasCauseInstanceOf(IllegalArgumentException.class).cause()
.hasMessageContaining("Parse attempt failed for value [210302]")
.hasCauseInstanceOf(DateTimeParseException.class).cause()
@@ -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.
@@ -16,7 +16,6 @@
package org.springframework.scheduling.concurrent;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.ThreadPoolExecutor;
@@ -27,8 +26,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.core.task.NoOpRunnable;
import org.springframework.core.task.TaskDecorator;
import org.springframework.util.Assert;
import static org.assertj.core.api.Assertions.assertThatCode;
@@ -72,40 +69,10 @@ class ConcurrentTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
}
@Test
void earlySetConcurrentExecutorCallRespectsConfiguredTaskDecorator() {
void passingNullExecutorToSetterResultsInDefaultTaskExecutorBeingUsed() {
ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor();
executor.setConcurrentExecutor(new DecoratedExecutor());
executor.setTaskDecorator(new RunnableDecorator());
executor.setConcurrentExecutor(null);
assertThatCode(() -> executor.execute(new NoOpRunnable())).doesNotThrowAnyException();
}
@Test
void lateSetConcurrentExecutorCallRespectsConfiguredTaskDecorator() {
ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor();
executor.setTaskDecorator(new RunnableDecorator());
executor.setConcurrentExecutor(new DecoratedExecutor());
assertThatCode(() -> executor.execute(new NoOpRunnable())).doesNotThrowAnyException();
}
private static class DecoratedRunnable implements Runnable {
@Override
public void run() {
}
}
private static class RunnableDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
return new DecoratedRunnable();
}
}
private static class DecoratedExecutor implements Executor {
@Override
public void execute(Runnable command) {
Assert.state(command instanceof DecoratedRunnable, "TaskDecorator not applied");
}
}
}
@@ -82,17 +82,6 @@ public abstract class AnnotationVisitor {
this.av = annotationVisitor;
}
/**
* The annotation visitor to which this visitor must delegate method calls. May be {@literal
* null}.
*
* @return the annotation visitor to which this visitor must delegate method calls, or {@literal
* null}.
*/
public AnnotationVisitor getDelegate() {
return av;
}
/**
* Visits a primitive value of the annotation.
*
@@ -194,7 +194,7 @@ public class ClassReader {
this.b = classFileBuffer;
// Check the class' major_version. This field is after the magic and minor_version fields, which
// use 4 and 2 bytes respectively.
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V21) {
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V19) {
throw new IllegalArgumentException(
"Unsupported class file major version " + readShort(classFileOffset + 6));
}
@@ -308,7 +308,6 @@ public class ClassReader {
* @return the content of the given input stream.
* @throws IOException if a problem occurs during reading.
*/
@SuppressWarnings("PMD.UseTryWithResources")
private static byte[] readStream(final InputStream inputStream, final boolean close)
throws IOException {
if (inputStream == null) {
@@ -377,7 +376,7 @@ public class ClassReader {
}
/**
* Returns the internal name of the super class (see {@link Type#getInternalName()}). For
* Returns the internal of name of the super class (see {@link Type#getInternalName()}). For
* interfaces, the super class is {@link Object}.
*
* @return the internal name of the super class, or {@literal null} for {@link Object} class.
@@ -42,8 +42,7 @@ public final class ClassTooLargeException extends IndexOutOfBoundsException {
/**
* Constructs a new {@link ClassTooLargeException}.
*
* @param className the internal name of the class (see {@link
* org.objectweb.asm.Type#getInternalName()}).
* @param className the internal name of the class.
* @param constantPoolCount the number of constant pool items of the class.
*/
public ClassTooLargeException(final String className, final int constantPoolCount) {
@@ -53,7 +52,7 @@ public final class ClassTooLargeException extends IndexOutOfBoundsException {
}
/**
* Returns the internal name of the class (see {@link org.objectweb.asm.Type#getInternalName()}).
* Returns the internal name of the class.
*
* @return the internal name of the class.
*/
@@ -81,15 +81,6 @@ public abstract class ClassVisitor {
this.cv = classVisitor;
}
/**
* The class visitor to which this visitor must delegate method calls. May be {@literal null}.
*
* @return the class visitor to which this visitor must delegate method calls, or {@literal null}.
*/
public ClassVisitor getDelegate() {
return cv;
}
/**
* Visits the header of the class.
*
@@ -164,8 +155,7 @@ public abstract class ClassVisitor {
* implicitly its own nest, so it's invalid to call this method with the visited class name as
* argument.
*
* @param nestHost the internal name of the host class of the nest (see {@link
* Type#getInternalName()}).
* @param nestHost the internal name of the host class of the nest.
*/
public void visitNestHost(final String nestHost) {
if (api < Opcodes.ASM7) {
@@ -177,19 +167,14 @@ public abstract class ClassVisitor {
}
/**
* Visits the enclosing class of the class. This method must be called only if this class is a
* local or anonymous class. See the JVMS 4.7.7 section for more details.
* Visits the enclosing class of the class. This method must be called only if the class has an
* enclosing class.
*
* @param owner internal name of the enclosing class of the class (see {@link
* Type#getInternalName()}).
* @param owner internal name of the enclosing class of the class.
* @param name the name of the method that contains the class, or {@literal null} if the class is
* not enclosed in a method or constructor of its enclosing class (e.g. if it is enclosed in
* an instance initializer, static initializer, instance variable initializer, or class
* variable initializer).
* not enclosed in a method of its enclosing class.
* @param descriptor the descriptor of the method that contains the class, or {@literal null} if
* the class is not enclosed in a method or constructor of its enclosing class (e.g. if it is
* enclosed in an instance initializer, static initializer, instance variable initializer, or
* class variable initializer).
* the class is not enclosed in a method of its enclosing class.
*/
public void visitOuterClass(final String owner, final String name, final String descriptor) {
if (cv != null) {
@@ -256,7 +241,7 @@ public abstract class ClassVisitor {
* the visited class is the host of a nest. A nest host is implicitly a member of its own nest, so
* it's invalid to call this method with the visited class name as argument.
*
* @param nestMember the internal name of a nest member (see {@link Type#getInternalName()}).
* @param nestMember the internal name of a nest member.
*/
public void visitNestMember(final String nestMember) {
if (api < Opcodes.ASM7) {
@@ -271,8 +256,7 @@ public abstract class ClassVisitor {
* Visits a permitted subclasses. A permitted subclass is one of the allowed subclasses of the
* current class.
*
* @param permittedSubclass the internal name of a permitted subclass (see {@link
* Type#getInternalName()}).
* @param permittedSubclass the internal name of a permitted subclass.
*/
public void visitPermittedSubclass(final String permittedSubclass) {
if (api < Opcodes.ASM9) {
@@ -285,18 +269,15 @@ public abstract class ClassVisitor {
/**
* Visits information about an inner class. This inner class is not necessarily a member of the
* class being visited. More precisely, every class or interface C which is referenced by this
* class and which is not a package member must be visited with this method. This class must
* reference its nested class or interface members, and its enclosing class, if any. See the JVMS
* 4.7.6 section for more details.
* class being visited.
*
* @param name the internal name of C (see {@link Type#getInternalName()}).
* @param outerName the internal name of the class or interface C is a member of (see {@link
* Type#getInternalName()}). Must be {@literal null} if C is not the member of a class or
* interface (e.g. for local or anonymous classes).
* @param innerName the (simple) name of C. Must be {@literal null} for anonymous inner classes.
* @param access the access flags of C originally declared in the source code from which this
* class was compiled.
* @param name the internal name of an inner class (see {@link Type#getInternalName()}).
* @param outerName the internal name of the class to which the inner class belongs (see {@link
* Type#getInternalName()}). May be {@literal null} for not member classes.
* @param innerName the (simple) name of the inner class inside its enclosing class. May be
* {@literal null} for anonymous inner classes.
* @param access the access flags of the inner class as originally declared in the enclosing
* class.
*/
public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
@@ -842,7 +842,7 @@ public class ClassWriter extends ClassVisitor {
* constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
* sub classes, and is normally not needed by class generators or adapters.</i>
*
* @param value the internal name of the class (see {@link Type#getInternalName()}).
* @param value the internal name of the class.
* @return the index of a new or already existing class reference item.
*/
public int newClass(final String value) {
@@ -894,8 +894,7 @@ public class ClassWriter extends ClassVisitor {
* Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
* Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner the internal name of the field or method owner class (see {@link
* Type#getInternalName()}).
* @param owner the internal name of the field or method owner class.
* @param name the name of the field or method.
* @param descriptor the descriptor of the field or method.
* @return the index of a new or already existing method type reference item.
@@ -917,8 +916,7 @@ public class ClassWriter extends ClassVisitor {
* Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
* Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner the internal name of the field or method owner class (see {@link
* Type#getInternalName()}).
* @param owner the internal name of the field or method owner class.
* @param name the name of the field or method.
* @param descriptor the descriptor of the field or method.
* @param isInterface true if the owner is an interface.
@@ -980,7 +978,7 @@ public class ClassWriter extends ClassVisitor {
* constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
* sub classes, and is normally not needed by class generators or adapters.</i>
*
* @param owner the internal name of the field's owner class (see {@link Type#getInternalName()}).
* @param owner the internal name of the field's owner class.
* @param name the field's name.
* @param descriptor the field's descriptor.
* @return the index of a new or already existing field reference item.
@@ -994,8 +992,7 @@ public class ClassWriter extends ClassVisitor {
* constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
* sub classes, and is normally not needed by class generators or adapters.</i>
*
* @param owner the internal name of the method's owner class (see {@link
* Type#getInternalName()}).
* @param owner the internal name of the method's owner class.
* @param name the method's name.
* @param descriptor the method's descriptor.
* @param isInterface {@literal true} if {@code owner} is an interface.
@@ -1031,10 +1028,9 @@ public class ClassWriter extends ClassVisitor {
* currently being generated by this ClassWriter, which can of course not be loaded since it is
* under construction.
*
* @param type1 the internal name of a class (see {@link Type#getInternalName()}).
* @param type2 the internal name of another class (see {@link Type#getInternalName()}).
* @return the internal name of the common super class of the two given classes (see {@link
* Type#getInternalName()}).
* @param type1 the internal name of a class.
* @param type2 the internal name of another class.
* @return the internal name of the common super class of the two given classes.
*/
protected String getCommonSuperClass(final String type1, final String type2) {
ClassLoader classLoader = getClassLoader();
@@ -78,15 +78,6 @@ public abstract class FieldVisitor {
this.fv = fieldVisitor;
}
/**
* The field visitor to which this visitor must delegate method calls. May be {@literal null}.
*
* @return the field visitor to which this visitor must delegate method calls, or {@literal null}.
*/
public FieldVisitor getDelegate() {
return fv;
}
/**
* Visits an annotation of the field.
*
@@ -367,12 +367,11 @@ class Frame {
typeValue = REFERENCE_KIND | symbolTable.addType(internalName);
break;
default:
throw new IllegalArgumentException(
"Invalid descriptor fragment: " + buffer.substring(elementDescriptorOffset));
throw new IllegalArgumentException();
}
return ((elementDescriptorOffset - offset) << DIM_SHIFT) | typeValue;
default:
throw new IllegalArgumentException("Invalid descriptor: " + buffer.substring(offset));
throw new IllegalArgumentException();
}
}
@@ -65,7 +65,7 @@ public final class Handle {
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link
* Opcodes#H_INVOKEINTERFACE}.
* @param owner the internal name of the class that owns the field or method designated by this
* handle (see {@link Type#getInternalName()}).
* handle.
* @param name the name of the field or method designated by this handle.
* @param descriptor the descriptor of the field or method designated by this handle.
* @deprecated this constructor has been superseded by {@link #Handle(int, String, String, String,
@@ -85,7 +85,7 @@ public final class Handle {
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link
* Opcodes#H_INVOKEINTERFACE}.
* @param owner the internal name of the class that owns the field or method designated by this
* handle (see {@link Type#getInternalName()}).
* handle.
* @param name the name of the field or method designated by this handle.
* @param descriptor the descriptor of the field or method designated by this handle.
* @param isInterface whether the owner is an interface or not.
@@ -118,8 +118,7 @@ public final class Handle {
/**
* Returns the internal name of the class that owns the field or method designated by this handle.
*
* @return the internal name of the class that owns the field or method designated by this handle
* (see {@link Type#getInternalName()}).
* @return the internal name of the class that owns the field or method designated by this handle.
*/
public String getOwner() {
return owner;
@@ -44,7 +44,7 @@ public final class MethodTooLargeException extends IndexOutOfBoundsException {
/**
* Constructs a new {@link MethodTooLargeException}.
*
* @param className the internal name of the owner class (see {@link Type#getInternalName()}).
* @param className the internal name of the owner class.
* @param methodName the name of the method.
* @param descriptor the descriptor of the method.
* @param codeSize the size of the method's Code attribute, in bytes.
@@ -64,7 +64,7 @@ public final class MethodTooLargeException extends IndexOutOfBoundsException {
/**
* Returns the internal name of the owner class.
*
* @return the internal name of the owner class (see {@link Type#getInternalName()}).
* @return the internal name of the owner class.
*/
public String getClassName() {
return className;
@@ -94,16 +94,6 @@ public abstract class MethodVisitor {
this.mv = methodVisitor;
}
/**
* The method visitor to which this visitor must delegate method calls. May be {@literal null}.
*
* @return the method visitor to which this visitor must delegate method calls, or {@literal
* null}.
*/
public MethodVisitor getDelegate() {
return mv;
}
// -----------------------------------------------------------------------------------------------
// Parameters, annotations and non standard attributes
// -----------------------------------------------------------------------------------------------
@@ -130,7 +120,7 @@ public abstract class MethodVisitor {
* @return a visitor to the visit the actual default value of this annotation interface method, or
* {@literal null} if this visitor is not interested in visiting this default value. The
* 'name' parameters passed to the methods of this annotation visitor are ignored. Moreover,
* exactly one visit method must be called on this annotation visitor, followed by visitEnd.
* exacly one visit method must be called on this annotation visitor, followed by visitEnd.
*/
public AnnotationVisitor visitAnnotationDefault() {
if (mv != null) {
@@ -283,17 +273,15 @@ public abstract class MethodVisitor {
* @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded
* frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link
* Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
* @param numLocal the number of local variables in the visited frame. Long and double values
* count for one variable.
* @param numLocal the number of local variables in the visited frame.
* @param local the local variable types in this frame. This array must not be modified. Primitive
* types are represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link
* Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL} or
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a single element).
* Reference types are represented by String objects (representing internal names, see {@link
* Type#getInternalName()}), and uninitialized types by Label objects (this label designates
* the NEW instruction that created this uninitialized value).
* @param numStack the number of operand stack elements in the visited frame. Long and double
* values count for one stack element.
* Reference types are represented by String objects (representing internal names), and
* uninitialized types by Label objects (this label designates the NEW instruction that
* created this uninitialized value).
* @param numStack the number of operand stack elements in the visited frame.
* @param stack the operand stack types in this frame. This array must not be modified. Its
* content has the same format as the "local" array.
* @throws IllegalStateException if a frame is visited just after another one, without any
@@ -372,7 +360,7 @@ public abstract class MethodVisitor {
/**
* Visits a type instruction. A type instruction is an instruction that takes the internal name of
* a class as parameter (see {@link Type#getInternalName()}).
* a class as parameter.
*
* @param opcode the opcode of the type instruction to be visited. This opcode is either NEW,
* ANEWARRAY, CHECKCAST or INSTANCEOF.
@@ -564,12 +552,12 @@ public abstract class MethodVisitor {
/**
* Visits an IINC instruction.
*
* @param varIndex index of the local variable to be incremented.
* @param var index of the local variable to be incremented.
* @param increment amount to increment the local variable by.
*/
public void visitIincInsn(final int varIndex, final int increment) {
public void visitIincInsn(final int var, final int increment) {
if (mv != null) {
mv.visitIincInsn(varIndex, increment);
mv.visitIincInsn(var, increment);
}
}
@@ -655,9 +643,8 @@ public abstract class MethodVisitor {
* @param start the beginning of the exception handler's scope (inclusive).
* @param end the end of the exception handler's scope (exclusive).
* @param handler the beginning of the exception handler's code.
* @param type the internal name of the type of exceptions handled by the handler (see {@link
* Type#getInternalName()}), or {@literal null} to catch any exceptions (for "finally"
* blocks).
* @param type the internal name of the type of exceptions handled by the handler, or {@literal
* null} to catch any exceptions (for "finally" blocks).
* @throws IllegalArgumentException if one of the labels has already been visited by this visitor
* (by the {@link #visitLabel} method).
*/
@@ -284,8 +284,6 @@ public interface Opcodes {
int V17 = 0 << 16 | 61;
int V18 = 0 << 16 | 62;
int V19 = 0 << 16 | 63;
int V20 = 0 << 16 | 64;
int V21 = 0 << 16 | 65;
/**
* Version flag indicating that the class is using 'preview' features.
@@ -45,7 +45,7 @@ public abstract class RecordComponentVisitor {
/**
* The record visitor to which this visitor must delegate method calls. May be {@literal null}.
*/
protected RecordComponentVisitor delegate;
/*package-private*/ RecordComponentVisitor delegate;
/**
* Constructs a new {@link RecordComponentVisitor}.
@@ -83,8 +83,7 @@ public abstract class RecordComponentVisitor {
/**
* The record visitor to which this visitor must delegate method calls. May be {@literal null}.
*
* @return the record visitor to which this visitor must delegate method calls, or {@literal
* null}.
* @return the record visitor to which this visitor must delegate method calls or {@literal null}.
*/
public RecordComponentVisitor getDelegate() {
return delegate;
@@ -37,7 +37,7 @@ final class RecordComponentWriter extends RecordComponentVisitor {
/** The name_index field of the Record attribute. */
private final int nameIndex;
/** The descriptor_index field of the Record attribute. */
/** The descriptor_index field of the the Record attribute. */
private final int descriptorIndex;
/**
@@ -245,7 +245,7 @@ public final class Type {
/**
* Returns the {@link Type} corresponding to the given internal name.
*
* @param internalName an internal name (see {@link Type#getInternalName()}).
* @param internalName an internal name.
* @return the {@link Type} corresponding to the given internal name.
*/
public static Type getObjectType(final String internalName) {
@@ -708,8 +708,8 @@ public final class Type {
*
* @return the size of the arguments of the method (plus one for the implicit this argument),
* argumentsSize, and the size of its return value, returnSize, packed into a single int i =
* {@code (argumentsSize &lt;&lt; 2) | returnSize} (argumentsSize is therefore equal to {@code
* i &gt;&gt; 2}, and returnSize to {@code i &amp; 0x03}).
* {@code (argumentsSize << 2) | returnSize} (argumentsSize is therefore equal to {@code
* i >> 2}, and returnSize to {@code i & 0x03}).
*/
public int getArgumentsAndReturnSizes() {
return getArgumentsAndReturnSizes(getDescriptor());
@@ -721,8 +721,8 @@ public final class Type {
* @param methodDescriptor a method descriptor.
* @return the size of the arguments of the method (plus one for the implicit this argument),
* argumentsSize, and the size of its return value, returnSize, packed into a single int i =
* {@code (argumentsSize &lt;&lt; 2) | returnSize} (argumentsSize is therefore equal to {@code
* i &gt;&gt; 2}, and returnSize to {@code i &amp; 0x03}).
* {@code (argumentsSize << 2) | returnSize} (argumentsSize is therefore equal to {@code
* i >> 2}, and returnSize to {@code i & 0x03}).
*/
public static int getArgumentsAndReturnSizes(final String methodDescriptor) {
int argumentsSize = 1;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -68,7 +68,6 @@ public final class CollectionFactory {
approximableCollectionTypes.add(SortedSet.class);
approximableCollectionTypes.add(NavigableSet.class);
approximableMapTypes.add(Map.class);
approximableMapTypes.add(MultiValueMap.class);
approximableMapTypes.add(SortedMap.class);
approximableMapTypes.add(NavigableMap.class);
@@ -81,7 +80,6 @@ public final class CollectionFactory {
approximableCollectionTypes.add(EnumSet.class);
approximableMapTypes.add(HashMap.class);
approximableMapTypes.add(LinkedHashMap.class);
approximableMapTypes.add(LinkedMultiValueMap.class);
approximableMapTypes.add(TreeMap.class);
approximableMapTypes.add(EnumMap.class);
}
@@ -123,7 +121,13 @@ public final class CollectionFactory {
*/
@SuppressWarnings({"rawtypes", "unchecked", "cast"})
public static <E> Collection<E> createApproximateCollection(@Nullable Object collection, int capacity) {
if (collection instanceof EnumSet) {
if (collection instanceof LinkedList) {
return new LinkedList<>();
}
else if (collection instanceof List) {
return new ArrayList<>(capacity);
}
else if (collection instanceof EnumSet) {
// Cast is necessary for compilation in Eclipse 4.4.1.
Collection<E> enumSet = (Collection<E>) EnumSet.copyOf((EnumSet) collection);
enumSet.clear();
@@ -132,12 +136,6 @@ public final class CollectionFactory {
else if (collection instanceof SortedSet) {
return new TreeSet<>(((SortedSet<E>) collection).comparator());
}
if (collection instanceof LinkedList) {
return new LinkedList<>();
}
else if (collection instanceof List) {
return new ArrayList<>(capacity);
}
else {
return new LinkedHashSet<>(capacity);
}
@@ -183,7 +181,7 @@ public final class CollectionFactory {
@SuppressWarnings({"unchecked", "cast"})
public static <E> Collection<E> createCollection(Class<?> collectionType, @Nullable Class<?> elementType, int capacity) {
Assert.notNull(collectionType, "Collection type must not be null");
if (LinkedHashSet.class == collectionType ||
if (LinkedHashSet.class == collectionType || HashSet.class == collectionType ||
Set.class == collectionType || Collection.class == collectionType) {
return new LinkedHashSet<>(capacity);
}
@@ -193,8 +191,8 @@ public final class CollectionFactory {
else if (LinkedList.class == collectionType) {
return new LinkedList<>();
}
else if (TreeSet.class == collectionType || NavigableSet.class == collectionType ||
SortedSet.class == collectionType) {
else if (TreeSet.class == collectionType || NavigableSet.class == collectionType
|| SortedSet.class == collectionType) {
return new TreeSet<>();
}
else if (EnumSet.class.isAssignableFrom(collectionType)) {
@@ -202,9 +200,6 @@ public final class CollectionFactory {
// Cast is necessary for compilation in Eclipse 4.4.1.
return (Collection<E>) EnumSet.noneOf(asEnumType(elementType));
}
else if (HashSet.class == collectionType) {
return new HashSet<>(capacity);
}
else {
if (collectionType.isInterface() || !Collection.class.isAssignableFrom(collectionType)) {
throw new IllegalArgumentException("Unsupported Collection type: " + collectionType.getName());
@@ -256,9 +251,6 @@ public final class CollectionFactory {
else if (map instanceof SortedMap) {
return new TreeMap<>(((SortedMap<K, V>) map).comparator());
}
else if (map instanceof MultiValueMap) {
return new LinkedMultiValueMap(capacity);
}
else {
return new LinkedHashMap<>(capacity);
}
@@ -305,24 +297,26 @@ public final class CollectionFactory {
@SuppressWarnings({"rawtypes", "unchecked"})
public static <K, V> Map<K, V> createMap(Class<?> mapType, @Nullable Class<?> keyType, int capacity) {
Assert.notNull(mapType, "Map type must not be null");
if (LinkedHashMap.class == mapType || Map.class == mapType) {
return new LinkedHashMap<>(capacity);
}
else if (LinkedMultiValueMap.class == mapType || MultiValueMap.class == mapType) {
return new LinkedMultiValueMap();
}
else if (TreeMap.class == mapType || SortedMap.class == mapType || NavigableMap.class == mapType) {
return new TreeMap<>();
if (mapType.isInterface()) {
if (Map.class == mapType) {
return new LinkedHashMap<>(capacity);
}
else if (SortedMap.class == mapType || NavigableMap.class == mapType) {
return new TreeMap<>();
}
else if (MultiValueMap.class == mapType) {
return new LinkedMultiValueMap();
}
else {
throw new IllegalArgumentException("Unsupported Map interface: " + mapType.getName());
}
}
else if (EnumMap.class == mapType) {
Assert.notNull(keyType, "Cannot create EnumMap for unknown key type");
return new EnumMap(asEnumType(keyType));
}
else if (HashMap.class == mapType) {
return new HashMap<>(capacity);
}
else {
if (mapType.isInterface() || !Map.class.isAssignableFrom(mapType)) {
if (!Map.class.isAssignableFrom(mapType)) {
throw new IllegalArgumentException("Unsupported Map type: " + mapType.getName());
}
try {
@@ -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.
@@ -781,7 +781,6 @@ public class MethodParameter {
return new MethodParameter(this);
}
/**
* Create a new MethodParameter for the given method or constructor.
* <p>This is a convenience factory method for scenarios where a
@@ -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.
@@ -49,7 +49,7 @@ public class ConversionFailedException extends ConversionException {
@Nullable Object value, Throwable cause) {
super("Failed to convert from type [" + sourceType + "] to type [" + targetType +
"] for value [" + ObjectUtils.nullSafeConciseToString(value) + "]", cause);
"] for value '" + ObjectUtils.nullSafeToString(value) + "'", cause);
this.sourceType = sourceType;
this.targetType = targetType;
this.value = value;
@@ -57,8 +57,6 @@ package org.springframework.core.env;
* of property sources prior to application context {@code refresh()}.
*
* @author Chris Beams
* @author Phillip Webb
* @author Sam Brannen
* @since 3.1
* @see PropertyResolver
* @see EnvironmentCapable
@@ -97,56 +95,25 @@ public interface Environment extends PropertyResolver {
String[] getDefaultProfiles();
/**
* Determine whether one or more of the given profiles is active &mdash; or
* in the case of no explicit {@linkplain #getActiveProfiles() active profiles},
* whether one or more of the given profiles is included in the set of
* {@linkplain #getDefaultProfiles() default profiles}.
* <p>If a profile begins with '!' the logic is inverted, meaning this method
* will return {@code true} if the given profile is <em>not</em> active. For
* example, {@code env.acceptsProfiles("p1", "!p2")} will return {@code true}
* if profile 'p1' is active or 'p2' is not active.
* @throws IllegalArgumentException if called with a {@code null} array, an
* empty array, zero arguments or if any profile is {@code null}, empty, or
* whitespace only
* Return whether one or more of the given profiles is active or, in the case of no
* explicit active profiles, whether one or more of the given profiles is included in
* the set of default profiles. If a profile begins with '!' the logic is inverted,
* i.e. the method will return {@code true} if the given profile is <em>not</em> active.
* For example, {@code env.acceptsProfiles("p1", "!p2")} will return {@code true} if
* profile 'p1' is active or 'p2' is not active.
* @throws IllegalArgumentException if called with zero arguments
* or if any profile is {@code null}, empty, or whitespace only
* @see #getActiveProfiles
* @see #getDefaultProfiles
* @see #matchesProfiles(String...)
* @see #acceptsProfiles(Profiles)
* @deprecated as of 5.1 in favor of {@link #acceptsProfiles(Profiles)} or
* {@link #matchesProfiles(String...)}
* @deprecated as of 5.1 in favor of {@link #acceptsProfiles(Profiles)}
*/
@Deprecated
boolean acceptsProfiles(String... profiles);
/**
* Determine whether one of the given profile expressions matches the
* {@linkplain #getActiveProfiles() active profiles} &mdash; or in the case
* of no explicit active profiles, whether one of the given profile expressions
* matches the {@linkplain #getDefaultProfiles() default profiles}.
* <p>Profile expressions allow for complex, boolean profile logic to be
* expressed &mdash; for example {@code "p1 & p2"}, {@code "(p1 & p2) | p3"},
* etc. See {@link Profiles#of(String...)} for details on the supported
* expression syntax.
* <p>This method is a convenient shortcut for
* {@code env.acceptsProfiles(Profiles.of(profileExpressions))}.
* @since 5.3.28
* @see Profiles#of(String...)
* @see #acceptsProfiles(Profiles)
*/
default boolean matchesProfiles(String... profileExpressions) {
return acceptsProfiles(Profiles.of(profileExpressions));
}
/**
* Determine whether the given {@link Profiles} predicate matches the
* {@linkplain #getActiveProfiles() active profiles} &mdash; or in the case
* of no explicit active profiles, whether the given {@code Profiles} predicate
* matches the {@linkplain #getDefaultProfiles() default profiles}.
* <p>If you wish provide profile expressions directly as strings, use
* {@link #matchesProfiles(String...)} instead.
* @since 5.1
* @see #matchesProfiles(String...)
* @see Profiles#of(String...)
* Return whether the {@linkplain #getActiveProfiles() active profiles}
* match the given {@link Profiles} predicate.
*/
boolean acceptsProfiles(Profiles profiles);
@@ -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.
@@ -43,32 +43,32 @@ public interface Profiles {
/**
* Create a new {@link Profiles} instance that checks for matches against
* the given <em>profile expressions</em>.
* the given <em>profile strings</em>.
* <p>The returned instance will {@linkplain Profiles#matches(Predicate) match}
* if any one of the given profile expressions matches.
* <p>A profile expression may contain a simple profile name (for example
* {@code "production"}) or a compound expression. A compound expression allows
* if any one of the given profile strings matches.
* <p>A profile string may contain a simple profile name (for example
* {@code "production"}) or a profile expression. A profile expression allows
* for more complicated profile logic to be expressed, for example
* {@code "production & cloud"}.
* <p>The following operators are supported in profile expressions.
* <ul>
* <li>{@code !} - A logical <em>NOT</em> of the profile name or compound expression</li>
* <li>{@code &} - A logical <em>AND</em> of the profile names or compound expressions</li>
* <li>{@code |} - A logical <em>OR</em> of the profile names or compound expressions</li>
* <li>{@code !} - A logical <em>NOT</em> of the profile or profile expression</li>
* <li>{@code &} - A logical <em>AND</em> of the profiles or profile expressions</li>
* <li>{@code |} - A logical <em>OR</em> of the profiles or profile expressions</li>
* </ul>
* <p>Please note that the {@code &} and {@code |} operators may not be mixed
* without using parentheses. For example, {@code "a & b | c"} is not a valid
* expression: it must be expressed as {@code "(a & b) | c"} or
* without using parentheses. For example {@code "a & b | c"} is not a valid
* expression; it must be expressed as {@code "(a & b) | c"} or
* {@code "a & (b | c)"}.
* <p>As of Spring Framework 5.1.17, two {@code Profiles} instances returned
* by this method are considered equivalent to each other (in terms of
* {@code equals()} and {@code hashCode()} semantics) if they are created
* with identical <em>profile expressions</em>.
* @param profileExpressions the <em>profile expressions</em> to include
* with identical <em>profile strings</em>.
* @param profiles the <em>profile strings</em> to include
* @return a new {@link Profiles} instance
*/
static Profiles of(String... profileExpressions) {
return ProfilesParser.parse(profileExpressions);
static Profiles of(String... profiles) {
return ProfilesParser.parse(profiles);
}
}
@@ -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.
@@ -43,7 +43,7 @@ final class ProfilesParser {
static Profiles parse(String... expressions) {
Assert.notEmpty(expressions, "Must specify at least one profile expression");
Assert.notEmpty(expressions, "Must specify at least one profile");
Profiles[] parsed = new Profiles[expressions.length];
for (int i = 0; i < expressions.length; i++) {
parsed[i] = parseExpression(expressions[i]);
@@ -71,8 +71,8 @@ final class ProfilesParser {
}
switch (token) {
case "(":
Profiles contents = parseTokens(expression, tokens, Context.PARENTHESIS);
if (context == Context.NEGATE) {
Profiles contents = parseTokens(expression, tokens, Context.BRACKET);
if (context == Context.INVERT) {
return contents;
}
elements.add(contents);
@@ -86,11 +86,11 @@ final class ProfilesParser {
operator = Operator.OR;
break;
case "!":
elements.add(not(parseTokens(expression, tokens, Context.NEGATE)));
elements.add(not(parseTokens(expression, tokens, Context.INVERT)));
break;
case ")":
Profiles merged = merge(expression, elements, operator);
if (context == Context.PARENTHESIS) {
if (context == Context.BRACKET) {
return merged;
}
elements.clear();
@@ -99,7 +99,7 @@ final class ProfilesParser {
break;
default:
Profiles value = equals(token);
if (context == Context.NEGATE) {
if (context == Context.INVERT) {
return value;
}
elements.add(value);
@@ -137,14 +137,15 @@ final class ProfilesParser {
return activeProfile -> activeProfile.test(profile);
}
private static Predicate<Profiles> isMatch(Predicate<String> activeProfiles) {
return profiles -> profiles.matches(activeProfiles);
private static Predicate<Profiles> isMatch(Predicate<String> activeProfile) {
return profiles -> profiles.matches(activeProfile);
}
private enum Operator { AND, OR }
private enum Operator {AND, OR}
private enum Context { NONE, NEGATE, PARENTHESIS }
private enum Context {NONE, INVERT, BRACKET}
private static class ParsedProfiles implements Profiles {
@@ -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.
@@ -23,7 +23,6 @@ import org.apache.commons.logging.Log;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* Utility methods for formatting and logging messages.
@@ -79,7 +78,7 @@ public abstract class LogFormatUtils {
result = ObjectUtils.nullSafeToString(ex);
}
if (maxLength != -1) {
result = StringUtils.truncate(result, maxLength);
result = (result.length() > maxLength ? result.substring(0, maxLength) + " (truncated)..." : result);
}
if (replaceNewlinesAndControlCharacters) {
result = NEWLINE_PATTERN.matcher(result).replaceAll("<EOL>");
@@ -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.
@@ -22,13 +22,12 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* A simple log message type for use with Commons Logging, allowing for convenient
* lazy resolution of a given {@link Supplier} instance (typically bound to a lambda
* expression) or a printf-style format string ({@link String#format}) in its
* {@link #toString()}.
* A simple log message type for use with Commons Logging, allowing
* for convenient lazy resolution of a given {@link Supplier} instance
* (typically bound to a Java 8 lambda expression) or a printf-style
* format string ({@link String#format}) in its {@link #toString()}.
*
* @author Juergen Hoeller
* @author Sebastien Deleuze
* @since 5.2
* @see #of(Supplier)
* @see #format(String, Object)
@@ -78,7 +77,7 @@ public abstract class LogMessage implements CharSequence {
/**
* Build a lazily resolving message from the given supplier.
* @param supplier the supplier (typically bound to a lambda expression)
* @param supplier the supplier (typically bound to a Java 8 lambda expression)
* @see #toString()
*/
public static LogMessage of(Supplier<? extends CharSequence> supplier) {
@@ -88,68 +87,63 @@ public abstract class LogMessage implements CharSequence {
/**
* Build a lazily formatted message from the given format string and argument.
* @param format the format string (following {@link String#format} rules)
* @param arg1 the argument (can be {@code null})
* @param arg1 the argument
* @see String#format(String, Object...)
*/
public static LogMessage format(String format, @Nullable Object arg1) {
public static LogMessage format(String format, Object arg1) {
return new FormatMessage1(format, arg1);
}
/**
* Build a lazily formatted message from the given format string and arguments.
* @param format the format string (following {@link String#format} rules)
* @param arg1 the first argument (can be {@code null})
* @param arg2 the second argument (can be {@code null})
* @param arg1 the first argument
* @param arg2 the second argument
* @see String#format(String, Object...)
*/
public static LogMessage format(String format, @Nullable Object arg1, @Nullable Object arg2) {
public static LogMessage format(String format, Object arg1, Object arg2) {
return new FormatMessage2(format, arg1, arg2);
}
/**
* Build a lazily formatted message from the given format string and arguments.
* @param format the format string (following {@link String#format} rules)
* @param arg1 the first argument (can be {@code null})
* @param arg2 the second argument (can be {@code null})
* @param arg3 the third argument (can be {@code null})
* @param arg1 the first argument
* @param arg2 the second argument
* @param arg3 the third argument
* @see String#format(String, Object...)
*/
public static LogMessage format(String format, @Nullable Object arg1, @Nullable Object arg2, @Nullable Object arg3) {
public static LogMessage format(String format, Object arg1, Object arg2, Object arg3) {
return new FormatMessage3(format, arg1, arg2, arg3);
}
/**
* Build a lazily formatted message from the given format string and arguments.
* @param format the format string (following {@link String#format} rules)
* @param arg1 the first argument (can be {@code null})
* @param arg2 the second argument (can be {@code null})
* @param arg3 the third argument (can be {@code null})
* @param arg4 the fourth argument (can be {@code null})
* @param arg1 the first argument
* @param arg2 the second argument
* @param arg3 the third argument
* @param arg4 the fourth argument
* @see String#format(String, Object...)
*/
public static LogMessage format(String format, @Nullable Object arg1, @Nullable Object arg2, @Nullable Object arg3,
@Nullable Object arg4) {
public static LogMessage format(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
return new FormatMessage4(format, arg1, arg2, arg3, arg4);
}
/**
* Build a lazily formatted message from the given format string and varargs.
* <p>This varargs {@code format()} variant may be costly. You should therefore
* use the individual argument variants whenever possible:
* {@link #format(String, Object)}, {@link #format(String, Object, Object)}, etc.
* @param format the format string (following {@link String#format} rules)
* @param args the varargs array (can be {@code null} and can contain {@code null}
* elements)
* @param args the varargs array (costly, prefer individual arguments)
* @see String#format(String, Object...)
*/
public static LogMessage format(String format, @Nullable Object... args) {
public static LogMessage format(String format, Object... args) {
return new FormatMessageX(format, args);
}
private static final class SupplierMessage extends LogMessage {
private final Supplier<? extends CharSequence> supplier;
private Supplier<? extends CharSequence> supplier;
SupplierMessage(Supplier<? extends CharSequence> supplier) {
Assert.notNull(supplier, "Supplier must not be null");
@@ -176,10 +170,9 @@ public abstract class LogMessage implements CharSequence {
private static final class FormatMessage1 extends FormatMessage {
@Nullable
private final Object arg1;
FormatMessage1(String format, @Nullable Object arg1) {
FormatMessage1(String format, Object arg1) {
super(format);
this.arg1 = arg1;
}
@@ -193,13 +186,11 @@ public abstract class LogMessage implements CharSequence {
private static final class FormatMessage2 extends FormatMessage {
@Nullable
private final Object arg1;
@Nullable
private final Object arg2;
FormatMessage2(String format, @Nullable Object arg1, @Nullable Object arg2) {
FormatMessage2(String format, Object arg1, Object arg2) {
super(format);
this.arg1 = arg1;
this.arg2 = arg2;
@@ -214,16 +205,13 @@ public abstract class LogMessage implements CharSequence {
private static final class FormatMessage3 extends FormatMessage {
@Nullable
private final Object arg1;
@Nullable
private final Object arg2;
@Nullable
private final Object arg3;
FormatMessage3(String format, @Nullable Object arg1, @Nullable Object arg2, @Nullable Object arg3) {
FormatMessage3(String format, Object arg1, Object arg2, Object arg3) {
super(format);
this.arg1 = arg1;
this.arg2 = arg2;
@@ -239,20 +227,15 @@ public abstract class LogMessage implements CharSequence {
private static final class FormatMessage4 extends FormatMessage {
@Nullable
private final Object arg1;
@Nullable
private final Object arg2;
@Nullable
private final Object arg3;
@Nullable
private final Object arg4;
FormatMessage4(String format, @Nullable Object arg1, @Nullable Object arg2, @Nullable Object arg3,
@Nullable Object arg4) {
FormatMessage4(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
super(format);
this.arg1 = arg1;
this.arg2 = arg2;
@@ -269,10 +252,9 @@ public abstract class LogMessage implements CharSequence {
private static final class FormatMessageX extends FormatMessage {
@Nullable
private final Object[] args;
FormatMessageX(String format, @Nullable Object... args) {
FormatMessageX(String format, Object... args) {
super(format);
this.args = args;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,7 +50,6 @@ public class DefaultDeserializer implements Deserializer<Object> {
/**
* Create a {@code DefaultDeserializer} for using an {@link ObjectInputStream}
* with the given {@code ClassLoader}.
* @param classLoader the ClassLoader to use
* @since 4.2.1
* @see ConfigurableObjectInputStream#ConfigurableObjectInputStream(InputStream, ClassLoader)
*/
@@ -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.
@@ -21,7 +21,6 @@ import java.io.ByteArrayInputStream;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.DefaultDeserializer;
import org.springframework.core.serializer.Deserializer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -51,11 +50,10 @@ public class DeserializingConverter implements Converter<byte[], Object> {
/**
* Create a {@code DeserializingConverter} for using an {@link java.io.ObjectInputStream}
* with the given {@code ClassLoader}.
* @param classLoader the ClassLoader to use
* @since 4.2.1
* @see DefaultDeserializer#DefaultDeserializer(ClassLoader)
*/
public DeserializingConverter(@Nullable ClassLoader classLoader) {
public DeserializingConverter(ClassLoader classLoader) {
this.deserializer = new DefaultDeserializer(classLoader);
}
@@ -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.
@@ -90,9 +90,4 @@ public class ExecutorServiceAdapter extends AbstractExecutorService {
return false;
}
// @Override on JDK 19
public void close() {
// no-op in order to avoid container-triggered shutdown call which would lead to exception logging
}
}
@@ -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.
@@ -68,10 +68,10 @@ public abstract class FileSystemUtils {
}
/**
* Delete the supplied {@link Path} &mdash; for directories,
* Delete the supplied {@link File} &mdash; for directories,
* recursively delete any nested directories or files as well.
* @param root the root {@code Path} to delete
* @return {@code true} if the {@code Path} existed and was deleted,
* @param root the root {@code File} to delete
* @return {@code true} if the {@code File} existed and was deleted,
* or {@code false} if it did not exist
* @throws IOException in the case of I/O errors
* @since 5.0
@@ -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.
@@ -64,7 +64,7 @@ public class InstanceFilter<T> {
/**
* Determine if the specified {@code instance} matches this filter.
* Determine if the specified {code instance} matches this filter.
*/
public boolean match(T instance) {
Assert.notNull(instance, "Instance to match must not be 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.
@@ -17,17 +17,11 @@
package org.springframework.util;
import java.lang.reflect.Array;
import java.net.URI;
import java.net.URL;
import java.time.temporal.Temporal;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.UUID;
import org.springframework.lang.Nullable;
@@ -659,7 +653,6 @@ public abstract class ObjectUtils {
* Returns a {@code "null"} String if {@code obj} is {@code null}.
* @param obj the object to build a String representation for
* @return a String representation of {@code obj}
* @see #nullSafeConciseToString(Object)
*/
public static String nullSafeToString(@Nullable Object obj) {
if (obj == null) {
@@ -915,70 +908,4 @@ public abstract class ObjectUtils {
return stringJoiner.toString();
}
/**
* Generate a null-safe, concise string representation of the supplied object
* as described below.
* <p>Favor this method over {@link #nullSafeToString(Object)} when you need
* the length of the generated string to be limited.
* <p>Returns:
* <ul>
* <li>{@code "null"} if {@code obj} is {@code null}</li>
* <li>{@linkplain Class#getName() Class name} if {@code obj} is a {@link Class}</li>
* <li>Potentially {@linkplain StringUtils#truncate(CharSequence) truncated string}
* if {@code obj} is a {@link String} or {@link CharSequence}</li>
* <li>Potentially {@linkplain StringUtils#truncate(CharSequence) truncated string}
* if {@code obj} is a <em>simple value type</em> whose {@code toString()} method
* returns a non-null value.</li>
* <li>Otherwise, a string representation of the object's type name concatenated
* with {@code @} and a hex string form of the object's identity hash code</li>
* </ul>
* <p>In the context of this method, a <em>simple value type</em> is any of the following:
* a primitive wrapper (excluding {@code Void}), an {@code Enum}, a {@code Number},
* a {@code Date}, a {@code Temporal}, a {@code UUID}, a {@code URI}, a {@code URL},
* or a {@code Locale}.
* @param obj the object to build a string representation for
* @return a concise string representation of the supplied object
* @since 5.3.27
* @see #nullSafeToString(Object)
* @see StringUtils#truncate(CharSequence)
*/
public static String nullSafeConciseToString(@Nullable Object obj) {
if (obj == null) {
return "null";
}
if (obj instanceof Class<?>) {
return ((Class<?>) obj).getName();
}
if (obj instanceof CharSequence) {
return StringUtils.truncate((CharSequence) obj);
}
Class<?> type = obj.getClass();
if (isSimpleValueType(type)) {
String str = obj.toString();
if (str != null) {
return StringUtils.truncate(str);
}
}
return type.getTypeName() + "@" + getIdentityHexString(obj);
}
/**
* Derived from {@link org.springframework.beans.BeanUtils#isSimpleValueType}.
* As of 5.3.28, considering {@code UUID} in addition to the bean-level check.
*/
private static boolean isSimpleValueType(Class<?> type) {
return (Void.class != type && void.class != type &&
(ClassUtils.isPrimitiveOrWrapper(type) ||
Enum.class.isAssignableFrom(type) ||
CharSequence.class.isAssignableFrom(type) ||
Number.class.isAssignableFrom(type) ||
Date.class.isAssignableFrom(type) ||
Temporal.class.isAssignableFrom(type) ||
UUID.class == type ||
URI.class == type ||
URL.class == type ||
Locale.class == type ||
Class.class == type));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -75,10 +75,6 @@ public abstract class StringUtils {
private static final char EXTENSION_SEPARATOR = '.';
private static final int DEFAULT_TRUNCATION_THRESHOLD = 100;
private static final String TRUNCATION_SUFFIX = " (truncated)...";
//---------------------------------------------------------------------
// General convenience methods for working with Strings
@@ -1392,40 +1388,4 @@ public abstract class StringUtils {
return arrayToDelimitedString(arr, ",");
}
/**
* Truncate the supplied {@link CharSequence}.
* <p>Delegates to {@link #truncate(CharSequence, int)}, supplying {@code 100}
* as the threshold.
* @param charSequence the {@code CharSequence} to truncate
* @return a truncated string, or a string representation of the original
* {@code CharSequence} if its length does not exceed the threshold
* @since 5.3.27
*/
public static String truncate(CharSequence charSequence) {
return truncate(charSequence, DEFAULT_TRUNCATION_THRESHOLD);
}
/**
* Truncate the supplied {@link CharSequence}.
* <p>If the length of the {@code CharSequence} is greater than the threshold,
* this method returns a {@linkplain CharSequence#subSequence(int, int)
* subsequence} of the {@code CharSequence} (up to the threshold) appended
* with the suffix {@code " (truncated)..."}. Otherwise, this method returns
* {@code charSequence.toString()}.
* @param charSequence the {@code CharSequence} to truncate
* @param threshold the maximum length after which to truncate; must be a
* positive number
* @return a truncated string, or a string representation of the original
* {@code CharSequence} if its length does not exceed the threshold
* @since 5.3.27
*/
public static String truncate(CharSequence charSequence, int threshold) {
Assert.isTrue(threshold > 0,
() -> "Truncation threshold must be a positive number: " + threshold);
if (charSequence.length() > threshold) {
return charSequence.subSequence(0, threshold) + TRUNCATION_SUFFIX;
}
return charSequence.toString();
}
}
@@ -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.
@@ -209,23 +209,21 @@ class CollectionFactoryTests {
@Test
void createsCollectionsCorrectly() {
// interfaces
testCollection(List.class, ArrayList.class);
testCollection(Set.class, LinkedHashSet.class);
testCollection(Collection.class, LinkedHashSet.class);
testCollection(SortedSet.class, TreeSet.class);
testCollection(NavigableSet.class, TreeSet.class);
assertThat(createCollection(List.class, 0)).isInstanceOf(ArrayList.class);
assertThat(createCollection(Set.class, 0)).isInstanceOf(LinkedHashSet.class);
assertThat(createCollection(Collection.class, 0)).isInstanceOf(LinkedHashSet.class);
assertThat(createCollection(SortedSet.class, 0)).isInstanceOf(TreeSet.class);
assertThat(createCollection(NavigableSet.class, 0)).isInstanceOf(TreeSet.class);
assertThat(createCollection(List.class, String.class, 0)).isInstanceOf(ArrayList.class);
assertThat(createCollection(Set.class, String.class, 0)).isInstanceOf(LinkedHashSet.class);
assertThat(createCollection(Collection.class, String.class, 0)).isInstanceOf(LinkedHashSet.class);
assertThat(createCollection(SortedSet.class, String.class, 0)).isInstanceOf(TreeSet.class);
assertThat(createCollection(NavigableSet.class, String.class, 0)).isInstanceOf(TreeSet.class);
// concrete types
testCollection(ArrayList.class, ArrayList.class);
testCollection(HashSet.class, HashSet.class);
testCollection(LinkedHashSet.class, LinkedHashSet.class);
testCollection(TreeSet.class, TreeSet.class);
}
private void testCollection(Class<?> collectionType, Class<?> resultType) {
assertThat(CollectionFactory.isApproximableCollectionType(collectionType)).isTrue();
assertThat(createCollection(collectionType, 0)).isExactlyInstanceOf(resultType);
assertThat(createCollection(collectionType, String.class, 0)).isExactlyInstanceOf(resultType);
assertThat(createCollection(HashSet.class, 0)).isInstanceOf(HashSet.class);
assertThat(createCollection(HashSet.class, String.class, 0)).isInstanceOf(HashSet.class);
}
@Test
@@ -260,22 +258,20 @@ class CollectionFactoryTests {
@Test
void createsMapsCorrectly() {
// interfaces
testMap(Map.class, LinkedHashMap.class);
testMap(SortedMap.class, TreeMap.class);
testMap(NavigableMap.class, TreeMap.class);
testMap(MultiValueMap.class, LinkedMultiValueMap.class);
assertThat(createMap(Map.class, 0)).isInstanceOf(LinkedHashMap.class);
assertThat(createMap(SortedMap.class, 0)).isInstanceOf(TreeMap.class);
assertThat(createMap(NavigableMap.class, 0)).isInstanceOf(TreeMap.class);
assertThat(createMap(MultiValueMap.class, 0)).isInstanceOf(LinkedMultiValueMap.class);
assertThat(createMap(Map.class, String.class, 0)).isInstanceOf(LinkedHashMap.class);
assertThat(createMap(SortedMap.class, String.class, 0)).isInstanceOf(TreeMap.class);
assertThat(createMap(NavigableMap.class, String.class, 0)).isInstanceOf(TreeMap.class);
assertThat(createMap(MultiValueMap.class, String.class, 0)).isInstanceOf(LinkedMultiValueMap.class);
// concrete types
testMap(HashMap.class, HashMap.class);
testMap(LinkedHashMap.class, LinkedHashMap.class);
testMap(TreeMap.class, TreeMap.class);
testMap(LinkedMultiValueMap.class, LinkedMultiValueMap.class);
}
assertThat(createMap(HashMap.class, 0)).isInstanceOf(HashMap.class);
private void testMap(Class<?> mapType, Class<?> resultType) {
assertThat(CollectionFactory.isApproximableMapType(mapType)).isTrue();
assertThat(createMap(mapType, 0)).isExactlyInstanceOf(resultType);
assertThat(createMap(mapType, String.class, 0)).isExactlyInstanceOf(resultType);
assertThat(createMap(HashMap.class, String.class, 0)).isInstanceOf(HashMap.class);
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,30 +40,30 @@ class ProfilesTests {
@Test
void ofWhenNullThrowsException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> Profiles.of((String[]) null))
.withMessage("Must specify at least one profile expression");
assertThatIllegalArgumentException().isThrownBy(() ->
Profiles.of((String[]) null))
.withMessageContaining("Must specify at least one profile");
}
@Test
void ofWhenEmptyThrowsException() {
assertThatIllegalArgumentException()
.isThrownBy(Profiles::of)
.withMessage("Must specify at least one profile expression");
.withMessageContaining("Must specify at least one profile");
}
@Test
void ofNullElement() {
assertThatIllegalArgumentException()
.isThrownBy(() -> Profiles.of((String) null))
.withMessage("Invalid profile expression [null]: must contain text");
assertThatIllegalArgumentException().isThrownBy(() ->
Profiles.of((String) null))
.withMessageContaining("must contain text");
}
@Test
void ofEmptyElement() {
assertThatIllegalArgumentException()
.isThrownBy(() -> Profiles.of(" "))
.withMessage("Invalid profile expression [ ]: must contain text");
assertThatIllegalArgumentException().isThrownBy(() ->
Profiles.of(" "))
.withMessageContaining("must contain text");
}
@Test
@@ -356,7 +356,7 @@ class ProfilesTests {
private static void assertMalformed(Supplier<Profiles> supplier) {
assertThatIllegalArgumentException()
.isThrownBy(supplier::get)
.withMessageStartingWith("Malformed profile expression");
.withMessageContaining("Malformed");
}
private static Predicate<String> activeProfiles(String... profiles) {
@@ -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.
@@ -18,9 +18,9 @@ package org.springframework.core.env;
import java.security.AccessControlException;
import java.security.Permission;
import java.util.Arrays;
import java.util.Map;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.core.SpringProperties;
@@ -40,7 +40,8 @@ import static org.springframework.core.env.AbstractEnvironment.RESERVED_DEFAULT_
* @author Juergen Hoeller
* @author Sam Brannen
*/
class StandardEnvironmentTests {
@SuppressWarnings("deprecation")
public class StandardEnvironmentTests {
private static final String ALLOWED_PROPERTY_NAME = "theanswer";
private static final String ALLOWED_PROPERTY_VALUE = "42";
@@ -80,8 +81,8 @@ class StandardEnvironmentTests {
assertThat(parent.getProperty("parentKey")).isEqualTo("parentVal");
assertThat(parent.getProperty("bothKey")).isEqualTo("parentBothVal");
assertThat(child.getActiveProfiles()).containsExactly("c1", "c2");
assertThat(parent.getActiveProfiles()).containsExactly("p1", "p2");
assertThat(child.getActiveProfiles()).isEqualTo(new String[]{"c1","c2"});
assertThat(parent.getActiveProfiles()).isEqualTo(new String[]{"p1","p2"});
child.merge(parent);
@@ -93,8 +94,8 @@ class StandardEnvironmentTests {
assertThat(parent.getProperty("parentKey")).isEqualTo("parentVal");
assertThat(parent.getProperty("bothKey")).isEqualTo("parentBothVal");
assertThat(child.getActiveProfiles()).containsExactly("c1", "c2", "p1", "p2");
assertThat(parent.getActiveProfiles()).containsExactly("p1", "p2");
assertThat(child.getActiveProfiles()).isEqualTo(new String[]{"c1","c2","p1","p2"});
assertThat(parent.getActiveProfiles()).isEqualTo(new String[]{"p1","p2"});
}
@Test
@@ -120,14 +121,16 @@ class StandardEnvironmentTests {
@Test
void defaultProfilesContainsDefaultProfileByDefault() {
assertThat(environment.getDefaultProfiles()).containsExactly("default");
assertThat(environment.getDefaultProfiles().length).isEqualTo(1);
assertThat(environment.getDefaultProfiles()[0]).isEqualTo("default");
}
@Test
void setActiveProfiles() {
environment.setActiveProfiles("local", "embedded");
String[] activeProfiles = environment.getActiveProfiles();
assertThat(activeProfiles).containsExactly("local", "embedded");
assertThat(activeProfiles).contains("local", "embedded");
assertThat(activeProfiles.length).isEqualTo(2);
}
@Test
@@ -174,12 +177,15 @@ class StandardEnvironmentTests {
void addActiveProfile() {
assertThat(environment.getActiveProfiles().length).isEqualTo(0);
environment.setActiveProfiles("local", "embedded");
assertThat(environment.getActiveProfiles()).containsExactly("local", "embedded");
assertThat(environment.getActiveProfiles()).contains("local", "embedded");
assertThat(environment.getActiveProfiles().length).isEqualTo(2);
environment.addActiveProfile("p1");
assertThat(environment.getActiveProfiles()).containsExactly("local", "embedded", "p1");
assertThat(environment.getActiveProfiles()).contains("p1");
assertThat(environment.getActiveProfiles().length).isEqualTo(3);
environment.addActiveProfile("p2");
environment.addActiveProfile("p3");
assertThat(environment.getActiveProfiles()).containsExactly("local", "embedded", "p1", "p2", "p3");
assertThat(environment.getActiveProfiles()).contains("p2", "p3");
assertThat(environment.getActiveProfiles().length).isEqualTo(5);
}
@Test
@@ -189,41 +195,65 @@ class StandardEnvironmentTests {
env.getPropertySources().addFirst(new MockPropertySource().withProperty(ACTIVE_PROFILES_PROPERTY_NAME, "p1"));
assertThat(env.getProperty(ACTIVE_PROFILES_PROPERTY_NAME)).isEqualTo("p1");
env.addActiveProfile("p2");
assertThat(env.getActiveProfiles()).containsExactly("p1", "p2");
assertThat(env.getActiveProfiles()).contains("p1", "p2");
}
@Test
void reservedDefaultProfile() {
assertThat(environment.getDefaultProfiles()).containsExactly(RESERVED_DEFAULT_PROFILE_NAME);
try {
System.setProperty(DEFAULT_PROFILES_PROPERTY_NAME, "d0");
assertThat(environment.getDefaultProfiles()).containsExactly("d0");
environment.setDefaultProfiles("d1", "d2");
assertThat(environment.getDefaultProfiles()).containsExactly("d1","d2");
}
finally {
System.clearProperty(DEFAULT_PROFILES_PROPERTY_NAME);
}
assertThat(environment.getDefaultProfiles()).isEqualTo(new String[]{RESERVED_DEFAULT_PROFILE_NAME});
System.setProperty(DEFAULT_PROFILES_PROPERTY_NAME, "d0");
assertThat(environment.getDefaultProfiles()).isEqualTo(new String[]{"d0"});
environment.setDefaultProfiles("d1", "d2");
assertThat(environment.getDefaultProfiles()).isEqualTo(new String[]{"d1","d2"});
System.clearProperty(DEFAULT_PROFILES_PROPERTY_NAME);
}
@Test
void defaultProfileWithCircularPlaceholder() {
try {
System.setProperty(DEFAULT_PROFILES_PROPERTY_NAME, "${spring.profiles.default}");
assertThatIllegalArgumentException()
.isThrownBy(environment::getDefaultProfiles)
.withMessage("Circular placeholder reference 'spring.profiles.default' in property definitions");
assertThatIllegalArgumentException().isThrownBy(environment::getDefaultProfiles);
}
finally {
System.clearProperty(DEFAULT_PROFILES_PROPERTY_NAME);
}
}
@Test
void getActiveProfiles_systemPropertiesEmpty() {
assertThat(environment.getActiveProfiles().length).isEqualTo(0);
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, "");
assertThat(environment.getActiveProfiles().length).isEqualTo(0);
System.clearProperty(ACTIVE_PROFILES_PROPERTY_NAME);
}
@Test
void getActiveProfiles_fromSystemProperties() {
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, "foo");
assertThat(Arrays.asList(environment.getActiveProfiles())).contains("foo");
System.clearProperty(ACTIVE_PROFILES_PROPERTY_NAME);
}
@Test
void getActiveProfiles_fromSystemProperties_withMultipleProfiles() {
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, "foo,bar");
assertThat(environment.getActiveProfiles()).contains("foo", "bar");
System.clearProperty(ACTIVE_PROFILES_PROPERTY_NAME);
}
@Test
void getActiveProfiles_fromSystemProperties_withMultipleProfiles_withWhitespace() {
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, " bar , baz "); // notice whitespace
assertThat(environment.getActiveProfiles()).contains("bar", "baz");
System.clearProperty(ACTIVE_PROFILES_PROPERTY_NAME);
}
@Test
void getDefaultProfiles() {
assertThat(environment.getDefaultProfiles()).containsExactly(RESERVED_DEFAULT_PROFILE_NAME);
assertThat(environment.getDefaultProfiles()).isEqualTo(new String[] {RESERVED_DEFAULT_PROFILE_NAME});
environment.getPropertySources().addFirst(new MockPropertySource().withProperty(DEFAULT_PROFILES_PROPERTY_NAME, "pd1"));
assertThat(environment.getDefaultProfiles()).containsExactly("pd1");
assertThat(environment.getDefaultProfiles().length).isEqualTo(1);
assertThat(Arrays.asList(environment.getDefaultProfiles())).contains("pd1");
}
@Test
@@ -231,9 +261,82 @@ class StandardEnvironmentTests {
environment.setDefaultProfiles();
assertThat(environment.getDefaultProfiles().length).isEqualTo(0);
environment.setDefaultProfiles("pd1");
assertThat(environment.getDefaultProfiles()).containsExactly("pd1");
assertThat(Arrays.asList(environment.getDefaultProfiles())).contains("pd1");
environment.setDefaultProfiles("pd2", "pd3");
assertThat(environment.getDefaultProfiles()).containsExactly("pd2", "pd3");
assertThat(environment.getDefaultProfiles()).doesNotContain("pd1");
assertThat(environment.getDefaultProfiles()).contains("pd2", "pd3");
}
@Test
void acceptsProfiles_withEmptyArgumentList() {
assertThatIllegalArgumentException().isThrownBy(
environment::acceptsProfiles);
}
@Test
void acceptsProfiles_withNullArgumentList() {
assertThatIllegalArgumentException().isThrownBy(() -> environment.acceptsProfiles((String[]) null));
}
@Test
void acceptsProfiles_withNullArgument() {
assertThatIllegalArgumentException().isThrownBy(() -> environment.acceptsProfiles((String) null));
}
@Test
void acceptsProfiles_withEmptyArgument() {
assertThatIllegalArgumentException().isThrownBy(() -> environment.acceptsProfiles(""));
}
@Test
void acceptsProfiles_activeProfileSetProgrammatically() {
assertThat(environment.acceptsProfiles("p1", "p2")).isFalse();
environment.setActiveProfiles("p1");
assertThat(environment.acceptsProfiles("p1", "p2")).isTrue();
environment.setActiveProfiles("p2");
assertThat(environment.acceptsProfiles("p1", "p2")).isTrue();
environment.setActiveProfiles("p1", "p2");
assertThat(environment.acceptsProfiles("p1", "p2")).isTrue();
}
@Test
void acceptsProfiles_activeProfileSetViaProperty() {
assertThat(environment.acceptsProfiles("p1")).isFalse();
environment.getPropertySources().addFirst(new MockPropertySource().withProperty(ACTIVE_PROFILES_PROPERTY_NAME, "p1"));
assertThat(environment.acceptsProfiles("p1")).isTrue();
}
@Test
void acceptsProfiles_defaultProfile() {
assertThat(environment.acceptsProfiles("pd")).isFalse();
environment.setDefaultProfiles("pd");
assertThat(environment.acceptsProfiles("pd")).isTrue();
environment.setActiveProfiles("p1");
assertThat(environment.acceptsProfiles("pd")).isFalse();
assertThat(environment.acceptsProfiles("p1")).isTrue();
}
@Test
void acceptsProfiles_withNotOperator() {
assertThat(environment.acceptsProfiles("p1")).isFalse();
assertThat(environment.acceptsProfiles("!p1")).isTrue();
environment.addActiveProfile("p1");
assertThat(environment.acceptsProfiles("p1")).isTrue();
assertThat(environment.acceptsProfiles("!p1")).isFalse();
}
@Test
void acceptsProfiles_withInvalidNotOperator() {
assertThatIllegalArgumentException().isThrownBy(() -> environment.acceptsProfiles("p1", "!"));
}
@Test
void acceptsProfiles_withProfileExpression() {
assertThat(environment.acceptsProfiles(Profiles.of("p1 & p2"))).isFalse();
environment.addActiveProfile("p1");
assertThat(environment.acceptsProfiles(Profiles.of("p1 & p2"))).isFalse();
environment.addActiveProfile("p2");
assertThat(environment.acceptsProfiles(Profiles.of("p1 & p2"))).isTrue();
}
@Test
@@ -243,99 +346,88 @@ class StandardEnvironmentTests {
protected void validateProfile(String profile) {
super.validateProfile(profile);
if (profile.contains("-")) {
throw new IllegalArgumentException("Invalid profile [" + profile + "]: must not contain dash character");
throw new IllegalArgumentException(
"Invalid profile [" + profile + "]: must not contain dash character");
}
}
};
env.addActiveProfile("validProfile"); // succeeds
assertThatIllegalArgumentException()
.isThrownBy(() -> env.addActiveProfile("invalid-profile"))
assertThatIllegalArgumentException().isThrownBy(() ->
env.addActiveProfile("invalid-profile"))
.withMessage("Invalid profile [invalid-profile]: must not contain dash character");
}
@Test
void suppressGetenvAccessThroughSystemProperty() {
try {
System.setProperty("spring.getenv.ignore", "true");
assertThat(environment.getSystemEnvironment()).isEmpty();
}
finally {
System.clearProperty("spring.getenv.ignore");
}
System.setProperty("spring.getenv.ignore", "true");
assertThat(environment.getSystemEnvironment().isEmpty()).isTrue();
System.clearProperty("spring.getenv.ignore");
}
@Test
void suppressGetenvAccessThroughSpringProperty() {
try {
SpringProperties.setProperty("spring.getenv.ignore", "true");
assertThat(environment.getSystemEnvironment()).isEmpty();
}
finally {
SpringProperties.setProperty("spring.getenv.ignore", null);
}
SpringProperties.setProperty("spring.getenv.ignore", "true");
assertThat(environment.getSystemEnvironment().isEmpty()).isTrue();
SpringProperties.setProperty("spring.getenv.ignore", null);
}
@Test
void suppressGetenvAccessThroughSpringFlag() {
try {
SpringProperties.setFlag("spring.getenv.ignore");
assertThat(environment.getSystemEnvironment()).isEmpty();
}
finally {
SpringProperties.setProperty("spring.getenv.ignore", null);
}
SpringProperties.setFlag("spring.getenv.ignore");
assertThat(environment.getSystemEnvironment().isEmpty()).isTrue();
SpringProperties.setProperty("spring.getenv.ignore", null);
}
@Test
void getSystemProperties_withAndWithoutSecurityManager() {
SecurityManager originalSecurityManager = System.getSecurityManager();
try {
System.setProperty(ALLOWED_PROPERTY_NAME, ALLOWED_PROPERTY_VALUE);
System.setProperty(DISALLOWED_PROPERTY_NAME, DISALLOWED_PROPERTY_VALUE);
System.getProperties().put(STRING_PROPERTY_NAME, NON_STRING_PROPERTY_VALUE);
System.getProperties().put(NON_STRING_PROPERTY_NAME, STRING_PROPERTY_VALUE);
System.setProperty(ALLOWED_PROPERTY_NAME, ALLOWED_PROPERTY_VALUE);
System.setProperty(DISALLOWED_PROPERTY_NAME, DISALLOWED_PROPERTY_VALUE);
System.getProperties().put(STRING_PROPERTY_NAME, NON_STRING_PROPERTY_VALUE);
System.getProperties().put(NON_STRING_PROPERTY_NAME, STRING_PROPERTY_VALUE);
{
Map<?, ?> systemProperties = environment.getSystemProperties();
assertThat(systemProperties).isNotNull();
assertThat(System.getProperties()).isSameAs(systemProperties);
assertThat(systemProperties.get(ALLOWED_PROPERTY_NAME)).isEqualTo(ALLOWED_PROPERTY_VALUE);
assertThat(systemProperties.get(DISALLOWED_PROPERTY_NAME)).isEqualTo(DISALLOWED_PROPERTY_VALUE);
{
Map<?, ?> systemProperties = environment.getSystemProperties();
assertThat(systemProperties).isNotNull();
assertThat(System.getProperties()).isSameAs(systemProperties);
assertThat(systemProperties.get(ALLOWED_PROPERTY_NAME)).isEqualTo(ALLOWED_PROPERTY_VALUE);
assertThat(systemProperties.get(DISALLOWED_PROPERTY_NAME)).isEqualTo(DISALLOWED_PROPERTY_VALUE);
// non-string keys and values work fine... until the security manager is introduced below
assertThat(systemProperties.get(STRING_PROPERTY_NAME)).isEqualTo(NON_STRING_PROPERTY_VALUE);
assertThat(systemProperties.get(NON_STRING_PROPERTY_NAME)).isEqualTo(STRING_PROPERTY_VALUE);
// non-string keys and values work fine... until the security manager is introduced below
assertThat(systemProperties.get(STRING_PROPERTY_NAME)).isEqualTo(NON_STRING_PROPERTY_VALUE);
assertThat(systemProperties.get(NON_STRING_PROPERTY_NAME)).isEqualTo(STRING_PROPERTY_VALUE);
}
SecurityManager oldSecurityManager = System.getSecurityManager();
SecurityManager securityManager = new SecurityManager() {
@Override
public void checkPropertiesAccess() {
// see https://download.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#getProperties()
throw new AccessControlException("Accessing the system properties is disallowed");
}
@Override
public void checkPropertyAccess(String key) {
// see https://download.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#getProperty(java.lang.String)
if (DISALLOWED_PROPERTY_NAME.equals(key)) {
throw new AccessControlException(
String.format("Accessing the system property [%s] is disallowed", DISALLOWED_PROPERTY_NAME));
}
}
@Override
public void checkPermission(Permission perm) {
// allow everything else
}
};
SecurityManager securityManager = new SecurityManager() {
@Override
public void checkPropertiesAccess() {
// see https://download.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#getProperties()
throw new AccessControlException("Accessing the system properties is disallowed");
}
@Override
public void checkPropertyAccess(String key) {
// see https://download.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#getProperty(java.lang.String)
if (DISALLOWED_PROPERTY_NAME.equals(key)) {
throw new AccessControlException(
String.format("Accessing the system property [%s] is disallowed", DISALLOWED_PROPERTY_NAME));
}
}
@Override
public void checkPermission(Permission perm) {
// allow everything else
}
};
try {
System.setSecurityManager(securityManager);
{
Map<?, ?> systemProperties = environment.getSystemProperties();
assertThat(systemProperties).isNotNull();
assertThat(systemProperties).isInstanceOf(ReadOnlySystemAttributesMap.class);
assertThat(systemProperties.get(ALLOWED_PROPERTY_NAME)).isEqualTo(ALLOWED_PROPERTY_VALUE);
assertThat((String)systemProperties.get(ALLOWED_PROPERTY_NAME)).isEqualTo(ALLOWED_PROPERTY_VALUE);
assertThat(systemProperties.get(DISALLOWED_PROPERTY_NAME)).isNull();
// nothing we can do here in terms of warning the user that there was
@@ -349,12 +441,12 @@ class StandardEnvironmentTests {
// the user that under these very special conditions (non-object key +
// SecurityManager that disallows access to system properties), they
// cannot do what they're attempting.
assertThatIllegalArgumentException().as("searching with non-string key against ReadOnlySystemAttributesMap")
.isThrownBy(() -> systemProperties.get(NON_STRING_PROPERTY_NAME));
assertThatIllegalArgumentException().as("searching with non-string key against ReadOnlySystemAttributesMap").isThrownBy(() ->
systemProperties.get(NON_STRING_PROPERTY_NAME));
}
}
finally {
System.setSecurityManager(originalSecurityManager);
System.setSecurityManager(oldSecurityManager);
System.clearProperty(ALLOWED_PROPERTY_NAME);
System.clearProperty(DISALLOWED_PROPERTY_NAME);
System.getProperties().remove(STRING_PROPERTY_NAME);
@@ -407,250 +499,4 @@ class StandardEnvironmentTests {
EnvironmentTestUtils.getModifiableSystemEnvironment().remove(DISALLOWED_PROPERTY_NAME);
}
@Nested
class GetActiveProfiles {
@Test
void systemPropertiesEmpty() {
assertThat(environment.getActiveProfiles()).isEmpty();
try {
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, "");
assertThat(environment.getActiveProfiles()).isEmpty();
}
finally {
System.clearProperty(ACTIVE_PROFILES_PROPERTY_NAME);
}
}
@Test
void fromSystemProperties() {
try {
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, "foo");
assertThat(environment.getActiveProfiles()).containsExactly("foo");
}
finally {
System.clearProperty(ACTIVE_PROFILES_PROPERTY_NAME);
}
}
@Test
void fromSystemProperties_withMultipleProfiles() {
try {
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, "foo,bar");
assertThat(environment.getActiveProfiles()).containsExactly("foo", "bar");
}
finally {
System.clearProperty(ACTIVE_PROFILES_PROPERTY_NAME);
}
}
@Test
void fromSystemProperties_withMultipleProfiles_withWhitespace() {
try {
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, " bar , baz "); // notice whitespace
assertThat(environment.getActiveProfiles()).containsExactly("bar", "baz");
}
finally {
System.clearProperty(ACTIVE_PROFILES_PROPERTY_NAME);
}
}
}
@Nested
class AcceptsProfilesTests {
@Test
@SuppressWarnings("deprecation")
void withEmptyArgumentList() {
assertThatIllegalArgumentException().isThrownBy(environment::acceptsProfiles);
}
@Test
@SuppressWarnings("deprecation")
void withNullArgumentList() {
assertThatIllegalArgumentException().isThrownBy(() -> environment.acceptsProfiles((String[]) null));
}
@Test
@SuppressWarnings("deprecation")
void withNullArgument() {
assertThatIllegalArgumentException().isThrownBy(() -> environment.acceptsProfiles((String) null));
}
@Test
@SuppressWarnings("deprecation")
void withEmptyArgument() {
assertThatIllegalArgumentException().isThrownBy(() -> environment.acceptsProfiles(""));
}
@Test
@SuppressWarnings("deprecation")
void activeProfileSetProgrammatically() {
assertThat(environment.acceptsProfiles("p1", "p2")).isFalse();
environment.setActiveProfiles("p1");
assertThat(environment.acceptsProfiles("p1", "p2")).isTrue();
environment.setActiveProfiles("p2");
assertThat(environment.acceptsProfiles("p1", "p2")).isTrue();
environment.setActiveProfiles("p1", "p2");
assertThat(environment.acceptsProfiles("p1", "p2")).isTrue();
}
@Test
@SuppressWarnings("deprecation")
void activeProfileSetViaProperty() {
assertThat(environment.acceptsProfiles("p1")).isFalse();
environment.getPropertySources().addFirst(new MockPropertySource().withProperty(ACTIVE_PROFILES_PROPERTY_NAME, "p1"));
assertThat(environment.acceptsProfiles("p1")).isTrue();
}
@Test
@SuppressWarnings("deprecation")
void defaultProfile() {
assertThat(environment.acceptsProfiles("pd")).isFalse();
environment.setDefaultProfiles("pd");
assertThat(environment.acceptsProfiles("pd")).isTrue();
environment.setActiveProfiles("p1");
assertThat(environment.acceptsProfiles("pd")).isFalse();
assertThat(environment.acceptsProfiles("p1")).isTrue();
}
@Test
@SuppressWarnings("deprecation")
void withNotOperator() {
assertThat(environment.acceptsProfiles("p1")).isFalse();
assertThat(environment.acceptsProfiles("!p1")).isTrue();
environment.addActiveProfile("p1");
assertThat(environment.acceptsProfiles("p1")).isTrue();
assertThat(environment.acceptsProfiles("!p1")).isFalse();
}
@Test
@SuppressWarnings("deprecation")
void withInvalidNotOperator() {
assertThatIllegalArgumentException().isThrownBy(() -> environment.acceptsProfiles("p1", "!"));
}
@Test
void withProfileExpression() {
assertThat(environment.acceptsProfiles(Profiles.of("p1 & p2"))).isFalse();
environment.addActiveProfile("p1");
assertThat(environment.acceptsProfiles(Profiles.of("p1 & p2"))).isFalse();
environment.addActiveProfile("p2");
assertThat(environment.acceptsProfiles(Profiles.of("p1 & p2"))).isTrue();
}
}
@Nested
class MatchesProfilesTests {
@Test
@SuppressWarnings("deprecation")
void withEmptyArgumentList() {
assertThatIllegalArgumentException().isThrownBy(environment::matchesProfiles);
}
@Test
@SuppressWarnings("deprecation")
void withNullArgumentList() {
assertThatIllegalArgumentException().isThrownBy(() -> environment.matchesProfiles((String[]) null));
}
@Test
@SuppressWarnings("deprecation")
void withNullArgument() {
assertThatIllegalArgumentException().isThrownBy(() -> environment.matchesProfiles((String) null));
assertThatIllegalArgumentException().isThrownBy(() -> environment.matchesProfiles("p1", null));
}
@Test
@SuppressWarnings("deprecation")
void withEmptyArgument() {
assertThatIllegalArgumentException().isThrownBy(() -> environment.matchesProfiles(""));
assertThatIllegalArgumentException().isThrownBy(() -> environment.matchesProfiles("p1", ""));
assertThatIllegalArgumentException().isThrownBy(() -> environment.matchesProfiles("p1", " "));
}
@Test
@SuppressWarnings("deprecation")
void withInvalidNotOperator() {
assertThatIllegalArgumentException().isThrownBy(() -> environment.matchesProfiles("p1", "!"));
}
@Test
@SuppressWarnings("deprecation")
void withInvalidCompoundExpressionGrouping() {
assertThatIllegalArgumentException().isThrownBy(() -> environment.matchesProfiles("p1 | p2 & p3"));
assertThatIllegalArgumentException().isThrownBy(() -> environment.matchesProfiles("p1 & p2 | p3"));
assertThatIllegalArgumentException().isThrownBy(() -> environment.matchesProfiles("p1 & (p2 | p3) | p4"));
}
@Test
@SuppressWarnings("deprecation")
void activeProfileSetProgrammatically() {
assertThat(environment.matchesProfiles("p1", "p2")).isFalse();
environment.setActiveProfiles("p1");
assertThat(environment.matchesProfiles("p1", "p2")).isTrue();
environment.setActiveProfiles("p2");
assertThat(environment.matchesProfiles("p1", "p2")).isTrue();
environment.setActiveProfiles("p1", "p2");
assertThat(environment.matchesProfiles("p1", "p2")).isTrue();
}
@Test
@SuppressWarnings("deprecation")
void activeProfileSetViaProperty() {
assertThat(environment.matchesProfiles("p1")).isFalse();
environment.getPropertySources().addFirst(new MockPropertySource().withProperty(ACTIVE_PROFILES_PROPERTY_NAME, "p1"));
assertThat(environment.matchesProfiles("p1")).isTrue();
}
@Test
@SuppressWarnings("deprecation")
void defaultProfile() {
assertThat(environment.matchesProfiles("pd")).isFalse();
environment.setDefaultProfiles("pd");
assertThat(environment.matchesProfiles("pd")).isTrue();
environment.setActiveProfiles("p1");
assertThat(environment.matchesProfiles("pd")).isFalse();
assertThat(environment.matchesProfiles("p1")).isTrue();
}
@Test
@SuppressWarnings("deprecation")
void withNotOperator() {
assertThat(environment.matchesProfiles("p1")).isFalse();
assertThat(environment.matchesProfiles("!p1")).isTrue();
environment.addActiveProfile("p1");
assertThat(environment.matchesProfiles("p1")).isTrue();
assertThat(environment.matchesProfiles("!p1")).isFalse();
}
@Test
void withProfileExpressions() {
assertThat(environment.matchesProfiles("p1 & p2")).isFalse();
environment.addActiveProfile("p1");
assertThat(environment.matchesProfiles("p1 | p2")).isTrue();
assertThat(environment.matchesProfiles("p1 & p2")).isFalse();
environment.addActiveProfile("p2");
assertThat(environment.matchesProfiles("p1 & p2")).isTrue();
assertThat(environment.matchesProfiles("p1 | p2")).isTrue();
assertThat(environment.matchesProfiles("foo | p1", "p2")).isTrue();
assertThat(environment.matchesProfiles("foo | p2", "p1")).isTrue();
assertThat(environment.matchesProfiles("foo | (p2 & p1)")).isTrue();
assertThat(environment.matchesProfiles("p2 & (foo | p1)")).isTrue();
assertThat(environment.matchesProfiles("foo", "(p2 & p1)")).isTrue();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,26 +17,15 @@
package org.springframework.util;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.ArrayList;
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.Set;
import java.util.UUID;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.springframework.util.ObjectUtils.isEmpty;
@@ -827,156 +816,13 @@ class ObjectUtilsTests {
.withMessage("Constant [bogus] does not exist in enum type org.springframework.util.ObjectUtilsTests$Tropes");
}
private static void assertEqualHashCodes(int expected, Object array) {
private void assertEqualHashCodes(int expected, Object array) {
int actual = ObjectUtils.nullSafeHashCode(array);
assertThat(actual).isEqualTo(expected);
assertThat(array.hashCode()).isNotEqualTo(actual);
assertThat(array.hashCode() != actual).isTrue();
}
enum Tropes {FOO, BAR, baz}
@Nested
class NullSafeConciseToStringTests {
private final String truncated = " (truncated)...";
private final int truncatedLength = 100 + truncated.length();
@Test
void nullSafeConciseToStringForNull() {
assertThat(ObjectUtils.nullSafeConciseToString(null)).isEqualTo("null");
}
@Test
void nullSafeConciseToStringForClass() {
assertThat(ObjectUtils.nullSafeConciseToString(String.class)).isEqualTo("java.lang.String");
}
@Test
void nullSafeConciseToStringForStrings() {
String repeat100 = repeat("X", 100);
String repeat101 = repeat("X", 101);
assertThat(ObjectUtils.nullSafeConciseToString("")).isEqualTo("");
assertThat(ObjectUtils.nullSafeConciseToString("foo")).isEqualTo("foo");
assertThat(ObjectUtils.nullSafeConciseToString(repeat100)).isEqualTo(repeat100);
assertThat(ObjectUtils.nullSafeConciseToString(repeat101)).hasSize(truncatedLength).endsWith(truncated);
}
@Test
void nullSafeConciseToStringForStringBuilders() {
String repeat100 = repeat("X", 100);
String repeat101 = repeat("X", 101);
assertThat(ObjectUtils.nullSafeConciseToString(new StringBuilder("foo"))).isEqualTo("foo");
assertThat(ObjectUtils.nullSafeConciseToString(new StringBuilder(repeat100))).isEqualTo(repeat100);
assertThat(ObjectUtils.nullSafeConciseToString(new StringBuilder(repeat101))).hasSize(truncatedLength).endsWith(truncated);
}
@Test
void nullSafeConciseToStringForEnum() {
assertThat(ObjectUtils.nullSafeConciseToString(Tropes.FOO)).isEqualTo("FOO");
}
@Test
void nullSafeConciseToStringForNumber() {
assertThat(ObjectUtils.nullSafeConciseToString(42L)).isEqualTo("42");
assertThat(ObjectUtils.nullSafeConciseToString(99.1234D)).isEqualTo("99.1234");
}
@Test
void nullSafeConciseToStringForDate() {
Date date = new Date();
assertThat(ObjectUtils.nullSafeConciseToString(date)).isEqualTo(date.toString());
}
@Test
void nullSafeConciseToStringForTemporal() {
LocalDate localDate = LocalDate.now();
assertThat(ObjectUtils.nullSafeConciseToString(localDate)).isEqualTo(localDate.toString());
}
@Test
void nullSafeConciseToStringForUUID() {
UUID id = UUID.randomUUID();
assertThat(ObjectUtils.nullSafeConciseToString(id)).isEqualTo(id.toString());
}
@Test
void nullSafeConciseToStringForURI() {
String uri = "https://www.example.com/?foo=1&bar=2&baz=3";
assertThat(ObjectUtils.nullSafeConciseToString(URI.create(uri))).isEqualTo(uri);
uri += "&qux=" + repeat("4", 60);
assertThat(ObjectUtils.nullSafeConciseToString(URI.create(uri)))
.hasSize(truncatedLength)
.startsWith(uri.subSequence(0, 100))
.endsWith(truncated);
}
@Test
void nullSafeConciseToStringForURL() throws Exception {
String url = "https://www.example.com/?foo=1&bar=2&baz=3";
assertThat(ObjectUtils.nullSafeConciseToString(new URL(url))).isEqualTo(url);
url += "&qux=" + repeat("4", 60);
assertThat(ObjectUtils.nullSafeConciseToString(new URL(url)))
.hasSize(truncatedLength)
.startsWith(url.subSequence(0, 100))
.endsWith(truncated);
}
@Test
void nullSafeConciseToStringForLocale() {
assertThat(ObjectUtils.nullSafeConciseToString(Locale.GERMANY)).isEqualTo("de_DE");
}
@Test
void nullSafeConciseToStringForArraysAndCollections() {
List<String> list = Arrays.asList("a", "b", "c");
assertThat(ObjectUtils.nullSafeConciseToString(new int[][] {{1, 2}, {3, 4}})).startsWith(prefix(int[][].class));
assertThat(ObjectUtils.nullSafeConciseToString(list.toArray(new Object[0]))).startsWith(prefix(Object[].class));
assertThat(ObjectUtils.nullSafeConciseToString(list.toArray(new String[0]))).startsWith(prefix(String[].class));
assertThat(ObjectUtils.nullSafeConciseToString(new ArrayList<>(list))).startsWith(prefix(ArrayList.class));
assertThat(ObjectUtils.nullSafeConciseToString(new HashSet<>(list))).startsWith(prefix(HashSet.class));
}
@Test
void nullSafeConciseToStringForCustomTypes() {
class ExplosiveType {
@Override
public String toString() {
throw new UnsupportedOperationException("no-go");
}
}
ExplosiveType explosiveType = new ExplosiveType();
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(explosiveType::toString);
assertThat(ObjectUtils.nullSafeConciseToString(explosiveType)).startsWith(prefix(ExplosiveType.class));
class WordyType {
@Override
public String toString() {
return repeat("blah blah", 20);
}
}
WordyType wordyType = new WordyType();
assertThat(wordyType).asString().hasSizeGreaterThanOrEqualTo(180 /* 9x20 */);
assertThat(ObjectUtils.nullSafeConciseToString(wordyType)).startsWith(prefix(WordyType.class));
}
private String repeat(String str, int count) {
String result = "";
for (int i = 0; i < count; i++) {
result += str;
}
return result;
}
private String prefix(Class<?> clazz) {
return clazz.getTypeName() + "@";
}
}
}
@@ -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.
@@ -22,8 +22,6 @@ import java.util.Locale;
import java.util.Properties;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
@@ -787,26 +785,4 @@ class StringUtilsTests {
assertThat(StringUtils.collectionToCommaDelimitedString(Collections.singletonList(null))).isEqualTo("null");
}
@Test
void truncatePreconditions() {
assertThatIllegalArgumentException()
.isThrownBy(() -> StringUtils.truncate("foo", 0))
.withMessage("Truncation threshold must be a positive number: 0");
assertThatIllegalArgumentException()
.isThrownBy(() -> StringUtils.truncate("foo", -99))
.withMessage("Truncation threshold must be a positive number: -99");
}
@ParameterizedTest
@CsvSource(delimiterString = "-->", value = {
"'' --> ''",
"aardvark --> aardvark",
"aardvark12 --> aardvark12",
"aardvark123 --> aardvark12 (truncated)...",
"aardvark, bird, cat --> aardvark, (truncated)..."
})
void truncate(String text, String truncated) {
assertThat(StringUtils.truncate(text, 10)).isEqualTo(truncated);
}
}
@@ -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.
@@ -17,7 +17,6 @@
package org.springframework.expression;
import java.util.List;
import java.util.function.Supplier;
import org.springframework.lang.Nullable;
@@ -25,21 +24,12 @@ import org.springframework.lang.Nullable;
* Expressions are executed in an evaluation context. It is in this context that
* references are resolved when encountered during expression evaluation.
*
* <p>There are two default implementations of this interface.
* <ul>
* <li>{@link org.springframework.expression.spel.support.SimpleEvaluationContext
* SimpleEvaluationContext}: a simpler builder-style {@code EvaluationContext}
* variant for data-binding purposes, which allows for opting into several SpEL
* features as needed.</li>
* <li>{@link org.springframework.expression.spel.support.StandardEvaluationContext
* StandardEvaluationContext}: a powerful and highly configurable {@code EvaluationContext}
* implementation, which can be extended, rather than having to implement everything
* manually.</li>
* </ul>
* <p>There is a default implementation of this EvaluationContext interface:
* {@link org.springframework.expression.spel.support.StandardEvaluationContext}
* which can be extended, rather than having to implement everything manually.
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.0
*/
public interface EvaluationContext {
@@ -95,30 +85,7 @@ public interface EvaluationContext {
OperatorOverloader getOperatorOverloader();
/**
* Assign the value created by the specified {@link Supplier} to a named variable
* within this evaluation context.
* <p>In contrast to {@link #setVariable(String, Object)}, this method should only
* be invoked to support the assignment operator ({@code =}) within an expression.
* <p>By default, this method delegates to {@code setVariable(String, Object)},
* providing the value created by the {@code valueSupplier}. Concrete implementations
* may override this <em>default</em> method to provide different semantics.
* @param name the name of the variable to assign
* @param valueSupplier the supplier of the value to be assigned to the variable
* @return a {@link TypedValue} wrapping the assigned value
* @since 5.2.24
*/
default TypedValue assignVariable(String name, Supplier<TypedValue> valueSupplier) {
TypedValue typedValue = valueSupplier.get();
setVariable(name, typedValue.getValue());
return typedValue;
}
/**
* Set a named variable in this evaluation context to a specified value.
* <p>In contrast to {@link #assignVariable(String, Supplier)}, this method
* should only be invoked programmatically when interacting directly with the
* {@code EvaluationContext} &mdash; for example, to provide initial
* configuration for the context.
* Set a named variable within this evaluation context to a specified value.
* @param name the name of the variable to set
* @param value the value to be placed in the variable
*/
@@ -126,7 +93,7 @@ public interface EvaluationContext {
/**
* Look up a named variable within this evaluation context.
* @param name the name of the variable to look up
* @param name variable to lookup
* @return the value of the variable, or {@code null} if not found
*/
@Nullable
@@ -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.
@@ -26,7 +26,6 @@ import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* An expression parser that understands templates. It can be subclassed by expression
@@ -35,7 +34,6 @@ import org.springframework.util.Assert;
* @author Keith Donald
* @author Juergen Hoeller
* @author Andy Clement
* @author Sam Brannen
* @since 3.0
*/
public abstract class TemplateAwareExpressionParser implements ExpressionParser {
@@ -48,11 +46,9 @@ public abstract class TemplateAwareExpressionParser implements ExpressionParser
@Override
public Expression parseExpression(String expressionString, @Nullable ParserContext context) throws ParseException {
if (context != null && context.isTemplate()) {
Assert.notNull(expressionString, "'expressionString' must not be null");
return parseTemplate(expressionString, context);
}
else {
Assert.hasText(expressionString, "'expressionString' must not be null or blank");
return doParseExpression(expressionString, context);
}
}
@@ -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.
@@ -23,7 +23,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.function.Supplier;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationContext;
@@ -39,19 +38,18 @@ import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* ExpressionState is for maintaining per-expression-evaluation state: any changes to
* it are not seen by other expressions, but it gives a place to hold local variables and
* An ExpressionState is for maintaining per-expression-evaluation state, any changes to
* it are not seen by other expressions but it gives a place to hold local variables and
* for component expressions in a compound expression to communicate state. This is in
* contrast to the EvaluationContext, which is shared amongst expression evaluations, and
* any changes to it will be seen by other expressions or any code that chooses to ask
* questions of the context.
*
* <p>It also acts as a place to define common utility routines that the various AST
* <p>It also acts as a place for to define common utility routines that the various AST
* nodes might need.
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.0
*/
public class ExpressionState {
@@ -140,29 +138,6 @@ public class ExpressionState {
return this.scopeRootObjects.element();
}
/**
* Assign the value created by the specified {@link Supplier} to a named variable
* within the evaluation context.
* <p>In contrast to {@link #setVariable(String, Object)}, this method should
* only be invoked to support assignment within an expression.
* @param name the name of the variable to assign
* @param valueSupplier the supplier of the value to be assigned to the variable
* @return a {@link TypedValue} wrapping the assigned value
* @since 5.2.24
* @see EvaluationContext#assignVariable(String, Supplier)
*/
public TypedValue assignVariable(String name, Supplier<TypedValue> valueSupplier) {
return this.relatedContext.assignVariable(name, valueSupplier);
}
/**
* Set a named variable in the evaluation context to a specified value.
* <p>In contrast to {@link #assignVariable(String, Supplier)}, this method
* should only be invoked programmatically.
* @param name the name of the variable to set
* @param value the value to be placed in the variable
* @see EvaluationContext#setVariable(String, Object)
*/
public void setVariable(String name, @Nullable Object value) {
this.relatedContext.setVariable(name, value);
}
@@ -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.
@@ -264,27 +264,7 @@ public enum SpelMessage {
/** @since 5.3.17 */
MAX_ARRAY_ELEMENTS_THRESHOLD_EXCEEDED(Kind.ERROR, 1075,
"Array declares too many elements, exceeding the threshold of ''{0}''"),
/** @since 5.2.23 */
MAX_REPEATED_TEXT_SIZE_EXCEEDED(Kind.ERROR, 1076,
"Repeated text is too long, exceeding the threshold of ''{0}'' characters"),
/** @since 5.2.23 */
MAX_REGEX_LENGTH_EXCEEDED(Kind.ERROR, 1077,
"Regular expression is too long, exceeding the threshold of ''{0}'' characters"),
/** @since 5.2.24 */
MAX_CONCATENATED_STRING_LENGTH_EXCEEDED(Kind.ERROR, 1078,
"Concatenated string is too long, exceeding the threshold of ''{0}'' characters"),
/** @since 5.2.24 */
MAX_EXPRESSION_LENGTH_EXCEEDED(Kind.ERROR, 1079,
"SpEL expression is too long, exceeding the threshold of ''{0}'' characters"),
/** @since 5.2.24 */
VARIABLE_ASSIGNMENT_NOT_SUPPORTED(Kind.ERROR, 1080,
"Assignment to variable ''{0}'' is not supported");
"Array declares too many elements, exceeding the threshold of ''{0}''");
private final Kind kind;
@@ -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.
@@ -30,12 +30,6 @@ import org.springframework.lang.Nullable;
*/
public class SpelParserConfiguration {
/**
* Default maximum length permitted for a SpEL expression.
* @since 5.2.24
*/
private static final int DEFAULT_MAX_EXPRESSION_LENGTH = 10_000;
/** System property to configure the default compiler mode for SpEL expression parsers: {@value}. */
public static final String SPRING_EXPRESSION_COMPILER_MODE_PROPERTY_NAME = "spring.expression.compiler.mode";
@@ -60,8 +54,6 @@ public class SpelParserConfiguration {
private final int maximumAutoGrowSize;
private final int maximumExpressionLength;
/**
* Create a new {@code SpelParserConfiguration} instance with default settings.
@@ -110,30 +102,11 @@ public class SpelParserConfiguration {
public SpelParserConfiguration(@Nullable SpelCompilerMode compilerMode, @Nullable ClassLoader compilerClassLoader,
boolean autoGrowNullReferences, boolean autoGrowCollections, int maximumAutoGrowSize) {
this(compilerMode, compilerClassLoader, autoGrowNullReferences, autoGrowCollections,
maximumAutoGrowSize, DEFAULT_MAX_EXPRESSION_LENGTH);
}
/**
* Create a new {@code SpelParserConfiguration} instance.
* @param compilerMode the compiler mode that parsers using this configuration object should use
* @param compilerClassLoader the ClassLoader to use as the basis for expression compilation
* @param autoGrowNullReferences if null references should automatically grow
* @param autoGrowCollections if collections should automatically grow
* @param maximumAutoGrowSize the maximum size that a collection can auto grow
* @param maximumExpressionLength the maximum length of a SpEL expression;
* must be a positive number
* @since 5.2.25
*/
public SpelParserConfiguration(@Nullable SpelCompilerMode compilerMode, @Nullable ClassLoader compilerClassLoader,
boolean autoGrowNullReferences, boolean autoGrowCollections, int maximumAutoGrowSize, int maximumExpressionLength) {
this.compilerMode = (compilerMode != null ? compilerMode : defaultCompilerMode);
this.compilerClassLoader = compilerClassLoader;
this.autoGrowNullReferences = autoGrowNullReferences;
this.autoGrowCollections = autoGrowCollections;
this.maximumAutoGrowSize = maximumAutoGrowSize;
this.maximumExpressionLength = maximumExpressionLength;
}
@@ -173,12 +146,4 @@ public class SpelParserConfiguration {
return this.maximumAutoGrowSize;
}
/**
* Return the maximum number of characters that a SpEL expression can contain.
* @since 5.2.25
*/
public int getMaximumExpressionLength() {
return this.maximumExpressionLength;
}
}
@@ -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.
@@ -27,7 +27,6 @@ import org.springframework.expression.spel.ExpressionState;
* <p>Example: 'someNumberProperty=42'
*
* @author Andy Clement
* @author Sam Brannen
* @since 3.0
*/
public class Assign extends SpelNodeImpl {
@@ -39,7 +38,9 @@ public class Assign extends SpelNodeImpl {
@Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
return this.children[0].setValueInternal(state, () -> this.children[1].getValueInternal(state));
TypedValue newValue = this.children[1].getValueInternal(state);
getChild(0).setValue(state, newValue.getValue());
return newValue;
}
@Override
@@ -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.
@@ -17,7 +17,6 @@
package org.springframework.expression.spel.ast;
import java.util.StringJoiner;
import java.util.function.Supplier;
import org.springframework.asm.MethodVisitor;
import org.springframework.expression.EvaluationException;
@@ -25,13 +24,13 @@ import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.CodeFlow;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.lang.Nullable;
/**
* Represents a DOT separated expression sequence, such as
* {@code 'property1.property2.methodOne()'}.
*
* @author Andy Clement
* @author Sam Brannen
* @since 3.0
*/
public class CompoundExpression extends SpelNodeImpl {
@@ -96,12 +95,8 @@ public class CompoundExpression extends SpelNodeImpl {
}
@Override
public TypedValue setValueInternal(ExpressionState state, Supplier<TypedValue> valueSupplier)
throws EvaluationException {
TypedValue typedValue = valueSupplier.get();
getValueRef(state).setValue(typedValue.getValue());
return typedValue;
public void setValue(ExpressionState state, @Nullable Object value) throws EvaluationException {
getValueRef(state).setValue(value);
}
@Override
@@ -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.
@@ -144,7 +144,7 @@ public class FunctionReference extends SpelNodeImpl {
for (int i = 0; i < getChildCount(); i++) {
sj.add(getChild(i).toStringAST());
}
return '#' + this.name + sj;
return '#' + this.name + sj.toString();
}
/**
@@ -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.
@@ -25,7 +25,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.function.Supplier;
import org.springframework.asm.MethodVisitor;
import org.springframework.core.convert.TypeDescriptor;
@@ -46,12 +45,11 @@ import org.springframework.util.ReflectionUtils;
/**
* An Indexer can index into some proceeding structure to access a particular piece of it.
* <p>Supported structures are: strings / collections (lists/sets) / arrays.
* Supported structures are: strings / collections (lists/sets) / arrays.
*
* @author Andy Clement
* @author Phillip Webb
* @author Stephane Nicoll
* @author Sam Brannen
* @since 3.0
*/
// TODO support multidimensional arrays
@@ -104,12 +102,8 @@ public class Indexer extends SpelNodeImpl {
}
@Override
public TypedValue setValueInternal(ExpressionState state, Supplier<TypedValue> valueSupplier)
throws EvaluationException {
TypedValue typedValue = valueSupplier.get();
getValueRef(state).setValue(typedValue.getValue());
return typedValue;
public void setValue(ExpressionState state, @Nullable Object newValue) throws EvaluationException {
getValueRef(state).setValue(newValue);
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -263,7 +263,7 @@ public class MethodReference extends SpelNodeImpl {
for (int i = 0; i < getChildCount(); i++) {
sj.add(getChild(i).toStringAST());
}
return this.name + sj;
return this.name + sj.toString();
}
/**
@@ -288,9 +288,12 @@ public class MethodReference extends SpelNodeImpl {
if (executor.didArgumentConversionOccur()) {
return false;
}
Class<?> clazz = executor.getMethod().getDeclaringClass();
return (Modifier.isPublic(clazz.getModifiers()) || executor.getPublicDeclaringClass() != null);
if (!Modifier.isPublic(clazz.getModifiers()) && executor.getPublicDeclaringClass() == null) {
return false;
}
return true;
}
@Override
@@ -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.
@@ -25,8 +25,6 @@ import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.CodeFlow;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.util.Assert;
import org.springframework.util.NumberUtils;
@@ -54,13 +52,6 @@ import org.springframework.util.NumberUtils;
*/
public class OpMultiply extends Operator {
/**
* Maximum number of characters permitted in repeated text.
* @since 5.2.23
*/
private static final int MAX_REPEATED_TEXT_SIZE = 256;
public OpMultiply(int startPos, int endPos, SpelNodeImpl... operands) {
super("*", startPos, endPos, operands);
}
@@ -118,13 +109,10 @@ public class OpMultiply extends Operator {
}
if (leftOperand instanceof String && rightOperand instanceof Integer) {
String text = (String) leftOperand;
int count = (Integer) rightOperand;
int requestedSize = text.length() * count;
checkRepeatedTextSize(requestedSize);
StringBuilder result = new StringBuilder(requestedSize);
for (int i = 0; i < count; i++) {
result.append(text);
int repeats = (Integer) rightOperand;
StringBuilder result = new StringBuilder();
for (int i = 0; i < repeats; i++) {
result.append(leftOperand);
}
return new TypedValue(result.toString());
}
@@ -132,13 +120,6 @@ public class OpMultiply extends Operator {
return state.operate(Operation.MULTIPLY, leftOperand, rightOperand);
}
private void checkRepeatedTextSize(int requestedSize) {
if (requestedSize > MAX_REPEATED_TEXT_SIZE) {
throw new SpelEvaluationException(getStartPosition(),
SpelMessage.MAX_REPEATED_TEXT_SIZE_EXCEEDED, MAX_REPEATED_TEXT_SIZE);
}
}
@Override
public boolean isCompilable() {
if (!getLeftOperand().isCompilable()) {
@@ -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.
@@ -27,8 +27,6 @@ import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.CodeFlow;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.NumberUtils;
@@ -48,18 +46,10 @@ import org.springframework.util.NumberUtils;
* @author Juergen Hoeller
* @author Ivo Smid
* @author Giovanni Dall'Oglio Risso
* @author Sam Brannen
* @since 3.0
*/
public class OpPlus extends Operator {
/**
* Maximum number of characters permitted in a concatenated string.
* @since 5.2.24
*/
private static final int MAX_CONCATENATED_STRING_LENGTH = 100_000;
public OpPlus(int startPos, int endPos, SpelNodeImpl... operands) {
super("+", startPos, endPos, operands);
Assert.notEmpty(operands, "Operands must not be empty");
@@ -133,45 +123,22 @@ public class OpPlus extends Operator {
if (leftOperand instanceof String && rightOperand instanceof String) {
this.exitTypeDescriptor = "Ljava/lang/String";
String leftString = (String) leftOperand;
String rightString = (String) rightOperand;
checkStringLength(leftString);
checkStringLength(rightString);
return concatenate(leftString, rightString);
return new TypedValue((String) leftOperand + rightOperand);
}
if (leftOperand instanceof String) {
String leftString = (String) leftOperand;
checkStringLength(leftString);
String rightString = (rightOperand == null ? "null" : convertTypedValueToString(operandTwoValue, state));
checkStringLength(rightString);
return concatenate(leftString, rightString);
return new TypedValue(
leftOperand + (rightOperand == null ? "null" : convertTypedValueToString(operandTwoValue, state)));
}
if (rightOperand instanceof String) {
String rightString = (String) rightOperand;
checkStringLength(rightString);
String leftString = (leftOperand == null ? "null" : convertTypedValueToString(operandOneValue, state));
checkStringLength(leftString);
return concatenate(leftString, rightString);
return new TypedValue(
(leftOperand == null ? "null" : convertTypedValueToString(operandOneValue, state)) + rightOperand);
}
return state.operate(Operation.ADD, leftOperand, rightOperand);
}
private void checkStringLength(String string) {
if (string.length() > MAX_CONCATENATED_STRING_LENGTH) {
throw new SpelEvaluationException(getStartPosition(),
SpelMessage.MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, MAX_CONCATENATED_STRING_LENGTH);
}
}
private TypedValue concatenate(String leftString, String rightString) {
String result = leftString + rightString;
checkStringLength(result);
return new TypedValue(result);
}
@Override
public String toStringAST() {
if (this.children.length < 2) { // unary plus
@@ -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.
@@ -36,41 +36,19 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.0
*/
public class OperatorMatches extends Operator {
private static final int PATTERN_ACCESS_THRESHOLD = 1000000;
/**
* Maximum number of characters permitted in a regular expression.
* @since 5.2.23
*/
private static final int MAX_REGEX_LENGTH = 1000;
private final ConcurrentMap<String, Pattern> patternCache;
private final ConcurrentMap<String, Pattern> patternCache = new ConcurrentHashMap<>();
/**
* Create a new {@link OperatorMatches} instance.
* @deprecated as of Spring Framework 5.2.23 in favor of invoking
* {@link #OperatorMatches(ConcurrentMap, int, int, SpelNodeImpl...)}
* with a shared pattern cache instead
*/
@Deprecated
public OperatorMatches(int startPos, int endPos, SpelNodeImpl... operands) {
this(new ConcurrentHashMap<>(), startPos, endPos, operands);
super("matches", startPos, endPos, operands);
}
/**
* Create a new {@link OperatorMatches} instance with a shared pattern cache.
* @since 5.2.23
*/
public OperatorMatches(ConcurrentMap<String, Pattern> patternCache, int startPos, int endPos, SpelNodeImpl... operands) {
super("matches", startPos, endPos, operands);
this.patternCache = patternCache;
}
/**
* Check the first operand matches the regex specified as the second operand.
@@ -84,28 +62,26 @@ public class OperatorMatches extends Operator {
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
SpelNodeImpl leftOp = getLeftOperand();
SpelNodeImpl rightOp = getRightOperand();
String left = leftOp.getValue(state, String.class);
Object right = getRightOperand().getValue(state);
String input = leftOp.getValue(state, String.class);
if (input == null) {
if (left == null) {
throw new SpelEvaluationException(leftOp.getStartPosition(),
SpelMessage.INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR, (Object) null);
}
Object right = rightOp.getValue(state);
if (!(right instanceof String)) {
throw new SpelEvaluationException(rightOp.getStartPosition(),
SpelMessage.INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR, right);
}
String regex = (String) right;
try {
Pattern pattern = this.patternCache.get(regex);
String rightString = (String) right;
Pattern pattern = this.patternCache.get(rightString);
if (pattern == null) {
checkRegexLength(regex);
pattern = Pattern.compile(regex);
this.patternCache.putIfAbsent(regex, pattern);
pattern = Pattern.compile(rightString);
this.patternCache.putIfAbsent(rightString, pattern);
}
Matcher matcher = pattern.matcher(new MatcherInput(input, new AccessCount()));
Matcher matcher = pattern.matcher(new MatcherInput(left, new AccessCount()));
return BooleanTypedValue.forValue(matcher.matches());
}
catch (PatternSyntaxException ex) {
@@ -118,13 +94,6 @@ public class OperatorMatches extends Operator {
}
}
private void checkRegexLength(String regex) {
if (regex.length() > MAX_REGEX_LENGTH) {
throw new SpelEvaluationException(getStartPosition(),
SpelMessage.MAX_REGEX_LENGTH_EXCEEDED, MAX_REGEX_LENGTH);
}
}
private static class AccessCount {
@@ -142,7 +111,7 @@ public class OperatorMatches extends Operator {
private final CharSequence value;
private final AccessCount access;
private AccessCount access;
public MatcherInput(CharSequence value, AccessCount access) {
this.value = value;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.springframework.asm.Label;
import org.springframework.asm.MethodVisitor;
@@ -47,7 +46,6 @@ import org.springframework.util.ReflectionUtils;
* @author Andy Clement
* @author Juergen Hoeller
* @author Clark Duplichien
* @author Sam Brannen
* @since 3.0
*/
public class PropertyOrFieldReference extends SpelNodeImpl {
@@ -149,12 +147,8 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
}
@Override
public TypedValue setValueInternal(ExpressionState state, Supplier<TypedValue> valueSupplier)
throws EvaluationException {
TypedValue typedValue = valueSupplier.get();
writeProperty(state.getActiveContextObject(), state.getEvaluationContext(), this.name, typedValue.getValue());
return typedValue;
public void setValue(ExpressionState state, @Nullable Object newValue) throws EvaluationException {
writeProperty(state.getActiveContextObject(), state.getEvaluationContext(), this.name, newValue);
}
@Override
@@ -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.
@@ -19,7 +19,6 @@ package org.springframework.expression.spel.ast;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.function.Supplier;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
@@ -41,7 +40,6 @@ import org.springframework.util.ObjectUtils;
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.0
*/
public abstract class SpelNodeImpl implements SpelNode, Opcodes {
@@ -66,7 +64,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
* <p>The descriptor is like the bytecode form but is slightly easier to work with.
* It does not include the trailing semicolon (for non array reference types).
* Some examples: Ljava/lang/String, I, [I
*/
*/
@Nullable
protected volatile String exitTypeDescriptor;
@@ -85,8 +83,8 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
/**
* Return {@code true} if the next child is one of the specified classes.
*/
* Return {@code true} if the next child is one of the specified classes.
*/
protected boolean nextChildIs(Class<?>... classes) {
if (this.parent != null) {
SpelNodeImpl[] peers = this.parent.children;
@@ -127,28 +125,6 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
@Override
public void setValue(ExpressionState expressionState, @Nullable Object newValue) throws EvaluationException {
setValueInternal(expressionState, () -> new TypedValue(newValue));
}
/**
* Evaluate the expression to a node and then set the new value created by the
* specified {@link Supplier} on that node.
* <p>For example, if the expression evaluates to a property reference, then the
* property will be set to the new value.
* <p>Favor this method over {@link #setValue(ExpressionState, Object)} when
* the value should be lazily computed.
* <p>By default, this method throws a {@link SpelEvaluationException},
* effectively disabling this feature. Subclasses may override this method to
* provide an actual implementation.
* @param expressionState the current expression state (includes the context)
* @param valueSupplier a supplier of the new value
* @throws EvaluationException if any problem occurs evaluating the expression or
* setting the new value
* @since 5.2.24
*/
public TypedValue setValueInternal(ExpressionState expressionState, Supplier<TypedValue> valueSupplier)
throws EvaluationException {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.SETVALUE_NOT_SUPPORTED, getClass());
}
@@ -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.
@@ -17,11 +17,9 @@
package org.springframework.expression.spel.ast;
import java.lang.reflect.Modifier;
import java.util.function.Supplier;
import org.springframework.asm.MethodVisitor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.CodeFlow;
import org.springframework.expression.spel.ExpressionState;
@@ -29,11 +27,10 @@ import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.lang.Nullable;
/**
* Represents a variable reference &mdash; for example, {@code #someVar}. Note
* that this is different than a <em>local</em> variable like {@code $someVar}.
* Represents a variable reference, eg. #someVar. Note this is different to a *local*
* variable like $someVar
*
* @author Andy Clement
* @author Sam Brannen
* @since 3.0
*/
public class VariableReference extends SpelNodeImpl {
@@ -56,14 +53,14 @@ public class VariableReference extends SpelNodeImpl {
@Override
public ValueRef getValueRef(ExpressionState state) throws SpelEvaluationException {
if (this.name.equals(THIS)) {
return new ValueRef.TypedValueHolderValueRef(state.getActiveContextObject(), this);
return new ValueRef.TypedValueHolderValueRef(state.getActiveContextObject(),this);
}
if (this.name.equals(ROOT)) {
return new ValueRef.TypedValueHolderValueRef(state.getRootContextObject(), this);
return new ValueRef.TypedValueHolderValueRef(state.getRootContextObject(),this);
}
TypedValue result = state.lookupVariable(this.name);
// a null value will mean either the value was null or the variable was not found
return new VariableRef(this.name, result, state.getEvaluationContext());
return new VariableRef(this.name,result,state.getEvaluationContext());
}
@Override
@@ -93,10 +90,8 @@ public class VariableReference extends SpelNodeImpl {
}
@Override
public TypedValue setValueInternal(ExpressionState state, Supplier<TypedValue> valueSupplier)
throws EvaluationException {
return state.assignVariable(this.name, valueSupplier);
public void setValue(ExpressionState state, @Nullable Object value) throws SpelEvaluationException {
state.setVariable(this.name, value);
}
@Override

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