mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2aeddb4fcb | |||
| 26cd33cb2b | |||
| 2ee393ae71 | |||
| 0815d29e45 | |||
| 777f01d786 | |||
| f8fea013fc | |||
| 916539178b | |||
| fdf3bcc9d9 | |||
| 5ddc984192 | |||
| b2ce54e7f1 | |||
| 937ab5f4b2 | |||
| 064c618050 | |||
| 8c80ec1138 | |||
| 912fa7602a | |||
| 525fc7a27e | |||
| 72285034ba | |||
| 933474000b | |||
| 4e8aebcde7 | |||
| dff5b1ff8e | |||
| fa0a4a0a46 | |||
| 41a6b7ec20 | |||
| cfaa4ba89c | |||
| 598e9d586b | |||
| 750a8b359f | |||
| c838bcff3a | |||
| 109b00d24d | |||
| b6abf45a56 | |||
| 2d94b43faa | |||
| f7f73439ab | |||
| 5e55558a93 | |||
| eee50d3b8a | |||
| 92af390ed2 | |||
| 332d2a36bb | |||
| 92b2b828f5 | |||
| a11222f681 | |||
| 7de8d81932 | |||
| 0e33537d9d | |||
| 00da70e26b | |||
| 72b44cebea | |||
| 1ee3777ac7 | |||
| cad6e8756d | |||
| c7bd685c54 | |||
| 4f472d2ac4 | |||
| a18842b72b | |||
| a41f97bc2b |
+11
-11
@@ -28,11 +28,11 @@ configure(allprojects) { project ->
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.7"
|
||||
mavenBom "io.netty:netty-bom:4.1.85.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.25"
|
||||
mavenBom "io.netty:netty-bom:4.1.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.49.v20220914"
|
||||
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"
|
||||
@@ -128,18 +128,18 @@ configure(allprojects) { project ->
|
||||
dependency "org.webjars:webjars-locator-core:0.48"
|
||||
dependency "org.webjars:underscorejs:1.8.3"
|
||||
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.68') {
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.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.68') {
|
||||
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.21.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,14 +191,14 @@ 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.23.0"
|
||||
dependency "org.assertj:assertj-core:3.24.1"
|
||||
dependencySet(group: 'org.xmlunit', version: '2.9.0') {
|
||||
entry 'xmlunit-assertj'
|
||||
entry('xmlunit-matchers') {
|
||||
exclude group: "org.hamcrest", name: "hamcrest-core"
|
||||
}
|
||||
}
|
||||
dependencySet(group: 'org.mockito', version: '4.8.1') {
|
||||
dependencySet(group: 'org.mockito', version: '4.9.0') { // spring-beans tests fail with 4.10+
|
||||
entry('mockito-core') {
|
||||
exclude group: "org.hamcrest", name: "hamcrest-core"
|
||||
}
|
||||
@@ -206,10 +206,10 @@ configure(allprojects) { project ->
|
||||
}
|
||||
dependency "io.mockk:mockk:1.12.1"
|
||||
|
||||
dependency("net.sourceforge.htmlunit:htmlunit:2.66.0") {
|
||||
dependency("net.sourceforge.htmlunit:htmlunit:2.69.0") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency("org.seleniumhq.selenium:htmlunit-driver:2.66.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") {
|
||||
@@ -340,7 +340,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
toolVersion = "10.4"
|
||||
toolVersion = "10.6.0"
|
||||
configDirectory.set(rootProject.file("src/checkstyle"))
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ ADD get-jdk-url.sh /get-jdk-url.sh
|
||||
RUN ./setup.sh java8
|
||||
|
||||
ENV JAVA_HOME /opt/openjdk/java8
|
||||
ENV JDK11 /opt/openjdk/java11
|
||||
ENV JDK17 /opt/openjdk/java17
|
||||
|
||||
ENV PATH $JAVA_HOME/bin:$PATH
|
||||
|
||||
@@ -5,15 +5,9 @@ case "$1" in
|
||||
java8)
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/8u345+1/bellsoft-jdk8u345+1-linux-amd64.tar.gz"
|
||||
;;
|
||||
java11)
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/11.0.16+8/bellsoft-jdk11.0.16+8-linux-amd64.tar.gz"
|
||||
;;
|
||||
java17)
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/17.0.4+8/bellsoft-jdk17.0.4+8-linux-amd64.tar.gz"
|
||||
;;
|
||||
java18)
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/18.0.2+10/bellsoft-jdk18.0.2+10-linux-amd64.tar.gz"
|
||||
;;
|
||||
*)
|
||||
echo $"Unknown java version"
|
||||
exit 1
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.4/c
|
||||
|
||||
mkdir -p /opt/openjdk
|
||||
pushd /opt/openjdk > /dev/null
|
||||
for jdk in java8 java11 java17
|
||||
for jdk in java8 java17
|
||||
do
|
||||
JDK_URL=$( /get-jdk-url.sh $jdk )
|
||||
mkdir $jdk
|
||||
|
||||
+2
-38
@@ -125,14 +125,6 @@ resources:
|
||||
access_token: ((github-ci-status-token))
|
||||
branch: ((branch))
|
||||
context: build
|
||||
- name: repo-status-jdk11-build
|
||||
type: github-status-resource
|
||||
icon: eye-check-outline
|
||||
source:
|
||||
repository: ((github-repo-name))
|
||||
access_token: ((github-ci-status-token))
|
||||
branch: ((branch))
|
||||
context: jdk11-build
|
||||
- name: repo-status-jdk17-build
|
||||
type: github-status-resource
|
||||
icon: eye-check-outline
|
||||
@@ -237,34 +229,6 @@ jobs:
|
||||
"zip.type": "schema"
|
||||
get_params:
|
||||
threads: 8
|
||||
- name: jdk11-build
|
||||
serial: true
|
||||
public: true
|
||||
plan:
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
- get: every-morning
|
||||
trigger: true
|
||||
- put: repo-status-jdk11-build
|
||||
params: { state: "pending", commit: "git-repo" }
|
||||
- do:
|
||||
- task: check-project
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/check-project.yml
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
params:
|
||||
TEST_TOOLCHAIN: 11
|
||||
<<: *build-project-task-params
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-jdk11-build
|
||||
params: { state: "failure", commit: "git-repo" }
|
||||
- put: slack-alert
|
||||
params:
|
||||
<<: *slack-fail-params
|
||||
- put: repo-status-jdk11-build
|
||||
params: { state: "success", commit: "git-repo" }
|
||||
- name: jdk17-build
|
||||
serial: true
|
||||
public: true
|
||||
@@ -282,7 +246,7 @@ jobs:
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
params:
|
||||
TEST_TOOLCHAIN: 15
|
||||
TEST_TOOLCHAIN: 17
|
||||
<<: *build-project-task-params
|
||||
on_failure:
|
||||
do:
|
||||
@@ -471,7 +435,7 @@ jobs:
|
||||
|
||||
groups:
|
||||
- name: "builds"
|
||||
jobs: ["build", "jdk11-build", "jdk17-build"]
|
||||
jobs: ["build", "jdk17-build"]
|
||||
- name: "releases"
|
||||
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release"]
|
||||
- name: "ci-images"
|
||||
|
||||
@@ -4,6 +4,6 @@ set -e
|
||||
source $(dirname $0)/common.sh
|
||||
|
||||
pushd git-repo > /dev/null
|
||||
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK11,JDK15 \
|
||||
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK17 \
|
||||
-PmainToolchain=${MAIN_TOOLCHAIN} -PtestToolchain=${TEST_TOOLCHAIN} --no-daemon --max-workers=4 check
|
||||
popd > /dev/null
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
version=5.3.24-SNAPSHOT
|
||||
version=5.3.25
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
org.gradle.caching=true
|
||||
org.gradle.parallel=true
|
||||
|
||||
@@ -81,6 +81,10 @@ plugins.withType(JavaPlugin) {
|
||||
javaLauncher = javaToolchains.launcherFor {
|
||||
languageVersion = testLanguageVersion
|
||||
}
|
||||
if(testLanguageVersion == JavaLanguageVersion.of(17)) {
|
||||
jvmArgs(["--add-opens=java.base/java.lang=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.util=ALL-UNNAMED"])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,21 +134,6 @@ pluginManager.withPlugin("kotlin") {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (testToolchainConfigured()) {
|
||||
def testLanguageVersion = testToolchainLanguageVersion()
|
||||
def compiler = javaToolchains.compilerFor {
|
||||
languageVersion = testLanguageVersion
|
||||
}
|
||||
// See https://kotlinlang.org/docs/gradle.html#attributes-specific-for-jvm
|
||||
def javaVersion = testLanguageVersion.toString() == '8' ? '1.8' : testLanguageVersion.toString()
|
||||
compileTestKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = javaVersion
|
||||
jdkHome = compiler.get().metadata.installationPath.asFile.absolutePath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the JMH plugin to use the toolchain for generating and running JMH bytecode
|
||||
|
||||
@@ -62,7 +62,7 @@ import org.springframework.util.StringUtils;
|
||||
* <p>Mainly for internal use within the framework, but to some degree also
|
||||
* useful for application classes. Consider
|
||||
* <a href="https://commons.apache.org/proper/commons-beanutils/">Apache Commons BeanUtils</a>,
|
||||
* <a href="https://hotelsdotcom.github.io/bull/">BULL - Bean Utils Light Library</a>,
|
||||
* <a href="https://github.com/ExpediaGroup/bull">BULL - Bean Utils Light Library</a>,
|
||||
* or similar third-party frameworks for more comprehensive bean utilities.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.beans;
|
||||
|
||||
import java.beans.BeanDescriptor;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.PropertyDescriptor;
|
||||
@@ -51,6 +52,10 @@ public class SimpleBeanInfoFactory implements BeanInfoFactory, Ordered {
|
||||
PropertyDescriptorUtils.determineBasicProperties(beanClass);
|
||||
|
||||
return new SimpleBeanInfo() {
|
||||
@Override
|
||||
public BeanDescriptor getBeanDescriptor() {
|
||||
return new BeanDescriptor(beanClass);
|
||||
}
|
||||
@Override
|
||||
public PropertyDescriptor[] getPropertyDescriptors() {
|
||||
return pds.toArray(PropertyDescriptorUtils.EMPTY_PROPERTY_DESCRIPTOR_ARRAY);
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -77,6 +77,21 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
|
||||
assertThat(accessor.getPropertyValue("aliasedName")).isEqualTo("tom");
|
||||
}
|
||||
|
||||
@Test
|
||||
void replaceWrappedInstance() {
|
||||
GetterBean target = new GetterBean();
|
||||
BeanWrapperImpl accessor = createAccessor(target);
|
||||
accessor.setPropertyValue("name", "tom");
|
||||
assertThat(target.getAliasedName()).isEqualTo("tom");
|
||||
assertThat(accessor.getPropertyValue("aliasedName")).isEqualTo("tom");
|
||||
|
||||
target = new GetterBean();
|
||||
accessor.setWrappedInstance(target);
|
||||
accessor.setPropertyValue("name", "tom");
|
||||
assertThat(target.getAliasedName()).isEqualTo("tom");
|
||||
assertThat(accessor.getPropertyValue("aliasedName")).isEqualTo("tom");
|
||||
}
|
||||
|
||||
@Test
|
||||
void setValidAndInvalidPropertyValuesShouldContainExceptionDetails() {
|
||||
TestBean target = new TestBean();
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -27,7 +27,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -148,7 +148,7 @@ public class QualifierAnnotationAutowireBeanFactoryTests {
|
||||
lbf.registerBeanDefinition(MARK, person2);
|
||||
MethodParameter param = new MethodParameter(QualifiedTestBean.class.getDeclaredConstructor(Person.class), 0);
|
||||
DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor(param, false);
|
||||
param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
param.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
|
||||
assertThat(param.getParameterName()).isEqualTo("tpb");
|
||||
assertThat(lbf.isAutowireCandidate(JUERGEN, null)).isTrue();
|
||||
assertThat(lbf.isAutowireCandidate(JUERGEN, qualifiedDescriptor)).isTrue();
|
||||
@@ -174,9 +174,9 @@ public class QualifierAnnotationAutowireBeanFactoryTests {
|
||||
new MethodParameter(QualifiedTestBean.class.getDeclaredMethod("autowireNonqualified", Person.class), 0);
|
||||
DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor(qualifiedParam, false);
|
||||
DependencyDescriptor nonqualifiedDescriptor = new DependencyDescriptor(nonqualifiedParam, false);
|
||||
qualifiedParam.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
qualifiedParam.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
|
||||
assertThat(qualifiedParam.getParameterName()).isEqualTo("tpb");
|
||||
nonqualifiedParam.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
nonqualifiedParam.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
|
||||
assertThat(nonqualifiedParam.getParameterName()).isEqualTo("tpb");
|
||||
assertThat(lbf.isAutowireCandidate(JUERGEN, null)).isTrue();
|
||||
assertThat(lbf.isAutowireCandidate(JUERGEN, nonqualifiedDescriptor)).isTrue();
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -502,7 +502,7 @@ class CustomEditorTests {
|
||||
CharBean cb = new CharBean();
|
||||
BeanWrapper bw = new BeanWrapperImpl(cb);
|
||||
|
||||
bw.setPropertyValue("myChar", new Character('c'));
|
||||
bw.setPropertyValue("myChar", 'c');
|
||||
assertThat(cb.getMyChar()).isEqualTo('c');
|
||||
|
||||
bw.setPropertyValue("myChar", "c");
|
||||
@@ -526,16 +526,16 @@ class CustomEditorTests {
|
||||
bw.registerCustomEditor(Character.class, new CharacterEditor(true));
|
||||
|
||||
bw.setPropertyValue("myCharacter", 'c');
|
||||
assertThat(cb.getMyCharacter()).isEqualTo(Character.valueOf('c'));
|
||||
assertThat(cb.getMyCharacter()).isEqualTo('c');
|
||||
|
||||
bw.setPropertyValue("myCharacter", "c");
|
||||
assertThat(cb.getMyCharacter()).isEqualTo(Character.valueOf('c'));
|
||||
assertThat(cb.getMyCharacter()).isEqualTo('c');
|
||||
|
||||
bw.setPropertyValue("myCharacter", "\u0041");
|
||||
assertThat(cb.getMyCharacter()).isEqualTo(Character.valueOf('A'));
|
||||
assertThat(cb.getMyCharacter()).isEqualTo('A');
|
||||
|
||||
bw.setPropertyValue("myCharacter", " ");
|
||||
assertThat(cb.getMyCharacter()).isEqualTo(Character.valueOf(' '));
|
||||
assertThat(cb.getMyCharacter()).isEqualTo(' ');
|
||||
|
||||
bw.setPropertyValue("myCharacter", "");
|
||||
assertThat(cb.getMyCharacter()).isNull();
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -20,7 +20,6 @@ import java.beans.PropertyDescriptor;
|
||||
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerFactory;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
@@ -32,6 +31,7 @@ import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.jmx.IJmxTestBean;
|
||||
import org.springframework.jmx.JmxTestBean;
|
||||
import org.springframework.jmx.export.TestDynamicMBean;
|
||||
import org.springframework.util.MBeanTestUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -41,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
class JmxUtilsTests {
|
||||
|
||||
@@ -131,10 +132,11 @@ class JmxUtilsTests {
|
||||
MBeanServer server = null;
|
||||
try {
|
||||
server = JmxUtils.locateMBeanServer();
|
||||
assertThat(server).isNotNull();
|
||||
}
|
||||
finally {
|
||||
if (server != null) {
|
||||
MBeanServerFactory.releaseMBeanServer(server);
|
||||
MBeanTestUtils.releaseMBeanServer(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,21 +21,25 @@ import java.lang.reflect.Field;
|
||||
import javax.naming.spi.NamingManager;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledForJreRange;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
||||
import static org.junit.jupiter.api.condition.JRE.JAVA_16;
|
||||
|
||||
/**
|
||||
* Tests for {@link JndiLocatorDelegate}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class JndiLocatorDelegateTests {
|
||||
@DisabledForJreRange(
|
||||
min = JAVA_16,
|
||||
disabledReason = "Cannot use reflection to set private static field in javax.naming.spi.NamingManager")
|
||||
class JndiLocatorDelegateTests {
|
||||
|
||||
@Test
|
||||
public void isDefaultJndiEnvironmentAvailableFalse() throws Exception {
|
||||
void isDefaultJndiEnvironmentAvailableFalse() throws Exception {
|
||||
Field builderField = NamingManager.class.getDeclaredField("initctx_factory_builder");
|
||||
builderField.setAccessible(true);
|
||||
Object oldBuilder = builderField.get(null);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,37 +18,59 @@ package org.springframework.util;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerFactory;
|
||||
|
||||
import org.junit.jupiter.api.condition.JRE;
|
||||
|
||||
/**
|
||||
* Utilities for MBean tests.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class MBeanTestUtils {
|
||||
|
||||
/**
|
||||
* Resets MBeanServerFactory and ManagementFactory to a known consistent state.
|
||||
* <p>This involves releasing all currently registered MBeanServers and resetting
|
||||
* the platformMBeanServer to null.
|
||||
* Reset the {@link MBeanServerFactory} to a known consistent state. This involves
|
||||
* {@linkplain #releaseMBeanServer(MBeanServer) releasing} all currently registered
|
||||
* MBeanServers.
|
||||
* <p>On JDK 8 - JDK 16, this method also resets the platformMBeanServer field
|
||||
* in {@link ManagementFactory} to {@code null}.
|
||||
*/
|
||||
public static synchronized void resetMBeanServers() throws Exception {
|
||||
for (MBeanServer server : MBeanServerFactory.findMBeanServer(null)) {
|
||||
try {
|
||||
MBeanServerFactory.releaseMBeanServer(server);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
if (!ex.getMessage().contains("not in list")) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
releaseMBeanServer(server);
|
||||
}
|
||||
|
||||
Field field = ManagementFactory.class.getDeclaredField("platformMBeanServer");
|
||||
field.setAccessible(true);
|
||||
field.set(null, null);
|
||||
if (!isCurrentJreWithinRange(JRE.JAVA_16, JRE.OTHER)) {
|
||||
Field field = ManagementFactory.class.getDeclaredField("platformMBeanServer");
|
||||
field.setAccessible(true);
|
||||
field.set(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to release the supplied {@link MBeanServer}.
|
||||
* <p>Ignores any {@link IllegalArgumentException} thrown by
|
||||
* {@link MBeanServerFactory#releaseMBeanServer(MBeanServer)} whose error
|
||||
* message contains the text "not in list".
|
||||
*/
|
||||
public static void releaseMBeanServer(MBeanServer server) {
|
||||
try {
|
||||
MBeanServerFactory.releaseMBeanServer(server);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
if (!ex.getMessage().contains("not in list")) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isCurrentJreWithinRange(JRE min, JRE max) {
|
||||
return EnumSet.range(min, max).contains(JRE.currentVersion());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,9 +18,9 @@ package org.springframework.core;
|
||||
|
||||
/**
|
||||
* Default implementation of the {@link ParameterNameDiscoverer} strategy interface,
|
||||
* using the Java 8 standard reflection mechanism (if available), and falling back
|
||||
* to the ASM-based {@link LocalVariableTableParameterNameDiscoverer} for checking
|
||||
* debug information in the class file.
|
||||
* using the Java 8 standard reflection mechanism, and falling back to the ASM-based
|
||||
* {@link LocalVariableTableParameterNameDiscoverer} for checking debug information
|
||||
* in the class file (e.g. for classes compiled with earlier Java versions).
|
||||
*
|
||||
* <p>If a Kotlin reflection implementation is present,
|
||||
* {@link KotlinReflectionParameterNameDiscoverer} is added first in the list and
|
||||
|
||||
+4
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -31,11 +31,13 @@ import org.springframework.lang.Nullable;
|
||||
* {@link ParameterNameDiscoverer} implementation which uses Kotlin's reflection facilities
|
||||
* for introspecting parameter names.
|
||||
*
|
||||
* Compared to {@link StandardReflectionParameterNameDiscoverer}, it allows in addition to
|
||||
* <p>Compared to {@link StandardReflectionParameterNameDiscoverer}, it allows in addition to
|
||||
* determine interface parameter names without requiring Java 8 -parameters compiler flag.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 5.0
|
||||
* @see StandardReflectionParameterNameDiscoverer
|
||||
* @see DefaultParameterNameDiscoverer
|
||||
*/
|
||||
public class KotlinReflectionParameterNameDiscoverer implements ParameterNameDiscoverer {
|
||||
|
||||
|
||||
+6
@@ -47,12 +47,18 @@ import org.springframework.util.ClassUtils;
|
||||
* caches the ASM discovered information for each introspected Class, in a thread-safe
|
||||
* manner. It is recommended to reuse ParameterNameDiscoverer instances as far as possible.
|
||||
*
|
||||
* <p>This discoverer variant is effectively superseded by the Java 8 based
|
||||
* {@link StandardReflectionParameterNameDiscoverer} but included as a fallback still
|
||||
* (for code not compiled with the standard "-parameters" compiler flag).
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @author Sam Brannen
|
||||
* @since 2.0
|
||||
* @see StandardReflectionParameterNameDiscoverer
|
||||
* @see DefaultParameterNameDiscoverer
|
||||
*/
|
||||
public class LocalVariableTableParameterNameDiscoverer implements ParameterNameDiscoverer {
|
||||
|
||||
|
||||
+6
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,10 +26,15 @@ import org.springframework.lang.Nullable;
|
||||
* {@link ParameterNameDiscoverer} implementation which uses JDK 8's reflection facilities
|
||||
* for introspecting parameter names (based on the "-parameters" compiler flag).
|
||||
*
|
||||
* <p>This is a key element of {@link DefaultParameterNameDiscoverer} where it is being
|
||||
* combined with {@link KotlinReflectionParameterNameDiscoverer} if Kotlin is present.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
* @see java.lang.reflect.Method#getParameters()
|
||||
* @see java.lang.reflect.Parameter#getName()
|
||||
* @see KotlinReflectionParameterNameDiscoverer
|
||||
* @see DefaultParameterNameDiscoverer
|
||||
*/
|
||||
public class StandardReflectionParameterNameDiscoverer implements ParameterNameDiscoverer {
|
||||
|
||||
|
||||
@@ -86,17 +86,6 @@ final class AttributeMethods {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if this instance only contains a single attribute named
|
||||
* {@code value}.
|
||||
* @return {@code true} if there is only a value attribute
|
||||
*/
|
||||
boolean hasOnlyValueAttribute() {
|
||||
return (this.attributeMethods.length == 1 &&
|
||||
MergedAnnotation.VALUE.equals(this.attributeMethods[0].getName()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if values from the given annotation can be safely accessed without
|
||||
* causing any {@link TypeNotPresentException TypeNotPresentExceptions}.
|
||||
|
||||
+2
-2
@@ -166,8 +166,8 @@ public abstract class RepeatableContainers {
|
||||
|
||||
private static Object computeRepeatedAnnotationsMethod(Class<? extends Annotation> annotationType) {
|
||||
AttributeMethods methods = AttributeMethods.forAnnotationType(annotationType);
|
||||
if (methods.hasOnlyValueAttribute()) {
|
||||
Method method = methods.get(0);
|
||||
Method method = methods.get(MergedAnnotation.VALUE);
|
||||
if (method != null) {
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (returnType.isArray()) {
|
||||
Class<?> componentType = returnType.getComponentType();
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework;
|
||||
|
||||
import org.junit.platform.suite.api.IncludeClassNamePatterns;
|
||||
import org.junit.platform.suite.api.SelectPackages;
|
||||
import org.junit.platform.suite.api.Suite;
|
||||
|
||||
/**
|
||||
* JUnit Platform based test suite for tests in the spring-core module.
|
||||
*
|
||||
* <p><strong>This suite is only intended to be used manually within an IDE.</strong>
|
||||
*
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@Suite
|
||||
@SelectPackages({"org.springframework.core", "org.springframework.util"})
|
||||
@IncludeClassNamePatterns(".*Tests?$")
|
||||
class SpringCoreTestSuite {
|
||||
}
|
||||
+9
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -34,7 +34,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
class LocalVariableTableParameterNameDiscovererTests {
|
||||
|
||||
private final LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
private final ParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
|
||||
@Test
|
||||
@@ -162,23 +162,23 @@ class LocalVariableTableParameterNameDiscovererTests {
|
||||
|
||||
Constructor<?> ctor = clazz.getDeclaredConstructor(Object.class);
|
||||
String[] names = discoverer.getParameterNames(ctor);
|
||||
assertThat(names.length).isEqualTo(1);
|
||||
assertThat(names).hasSize(1);
|
||||
assertThat(names[0]).isEqualTo("key");
|
||||
|
||||
ctor = clazz.getDeclaredConstructor(Object.class, Object.class);
|
||||
names = discoverer.getParameterNames(ctor);
|
||||
assertThat(names.length).isEqualTo(2);
|
||||
assertThat(names).hasSize(2);
|
||||
assertThat(names[0]).isEqualTo("key");
|
||||
assertThat(names[1]).isEqualTo("value");
|
||||
|
||||
Method m = clazz.getMethod("generifiedStaticMethod", Object.class);
|
||||
names = discoverer.getParameterNames(m);
|
||||
assertThat(names.length).isEqualTo(1);
|
||||
assertThat(names).hasSize(1);
|
||||
assertThat(names[0]).isEqualTo("param");
|
||||
|
||||
m = clazz.getMethod("generifiedMethod", Object.class, long.class, Object.class, Object.class);
|
||||
names = discoverer.getParameterNames(m);
|
||||
assertThat(names.length).isEqualTo(4);
|
||||
assertThat(names).hasSize(4);
|
||||
assertThat(names[0]).isEqualTo("param");
|
||||
assertThat(names[1]).isEqualTo("x");
|
||||
assertThat(names[2]).isEqualTo("key");
|
||||
@@ -186,21 +186,21 @@ class LocalVariableTableParameterNameDiscovererTests {
|
||||
|
||||
m = clazz.getMethod("voidStaticMethod", Object.class, long.class, int.class);
|
||||
names = discoverer.getParameterNames(m);
|
||||
assertThat(names.length).isEqualTo(3);
|
||||
assertThat(names).hasSize(3);
|
||||
assertThat(names[0]).isEqualTo("obj");
|
||||
assertThat(names[1]).isEqualTo("x");
|
||||
assertThat(names[2]).isEqualTo("i");
|
||||
|
||||
m = clazz.getMethod("nonVoidStaticMethod", Object.class, long.class, int.class);
|
||||
names = discoverer.getParameterNames(m);
|
||||
assertThat(names.length).isEqualTo(3);
|
||||
assertThat(names).hasSize(3);
|
||||
assertThat(names[0]).isEqualTo("obj");
|
||||
assertThat(names[1]).isEqualTo("x");
|
||||
assertThat(names[2]).isEqualTo("i");
|
||||
|
||||
m = clazz.getMethod("getDate");
|
||||
names = discoverer.getParameterNames(m);
|
||||
assertThat(names.length).isEqualTo(0);
|
||||
assertThat(names).isEmpty();
|
||||
}
|
||||
|
||||
@Disabled("Ignored because Ubuntu packages OpenJDK with debug symbols enabled. See SPR-8078.")
|
||||
|
||||
+3
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -43,11 +43,10 @@ import static org.junit.jupiter.api.condition.JRE.JAVA_14;
|
||||
@DisabledForJreRange(min = JAVA_14)
|
||||
public class SpringCoreBlockHoundIntegrationTests {
|
||||
|
||||
|
||||
@BeforeAll
|
||||
static void setUp() {
|
||||
static void setup() {
|
||||
BlockHound.builder()
|
||||
.with(new ReactorBlockHoundIntegration()) // Reactor non-blocking thread predicate
|
||||
.with(new ReactorBlockHoundIntegration()) // Reactor non-blocking thread predicate
|
||||
.with(new ReactiveAdapterRegistry.SpringCoreBlockHoundIntegration())
|
||||
.install();
|
||||
}
|
||||
|
||||
+47
@@ -20,6 +20,7 @@ import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@@ -77,6 +78,7 @@ import static org.springframework.core.annotation.AnnotationUtilsTests.asArray;
|
||||
* @see AnnotationUtilsTests
|
||||
* @see MultipleComposedAnnotationsOnSingleAnnotatedElementTests
|
||||
* @see ComposedRepeatableAnnotationsTests
|
||||
* @see NestedRepeatableAnnotationsTests
|
||||
*/
|
||||
class AnnotatedElementUtilsTests {
|
||||
|
||||
@@ -908,6 +910,31 @@ class AnnotatedElementUtilsTests {
|
||||
assertThat(annotation.value()).containsExactly("FromValueAttributeMeta");
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 5.3.25
|
||||
*/
|
||||
@Test // gh-29685
|
||||
void getMergedRepeatableAnnotationsWithContainerWithMultipleAttributes() {
|
||||
Set<StandardRepeatableWithContainerWithMultipleAttributes> repeatableAnnotations =
|
||||
AnnotatedElementUtils.getMergedRepeatableAnnotations(
|
||||
StandardRepeatablesWithContainerWithMultipleAttributesTestCase.class,
|
||||
StandardRepeatableWithContainerWithMultipleAttributes.class);
|
||||
assertThat(repeatableAnnotations).map(StandardRepeatableWithContainerWithMultipleAttributes::value)
|
||||
.containsExactly("a", "b");
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 5.3.25
|
||||
*/
|
||||
@Test // gh-29685
|
||||
void findMergedRepeatableAnnotationsWithContainerWithMultipleAttributes() {
|
||||
Set<StandardRepeatableWithContainerWithMultipleAttributes> repeatableAnnotations =
|
||||
AnnotatedElementUtils.findMergedRepeatableAnnotations(
|
||||
StandardRepeatablesWithContainerWithMultipleAttributesTestCase.class,
|
||||
StandardRepeatableWithContainerWithMultipleAttributes.class);
|
||||
assertThat(repeatableAnnotations).map(StandardRepeatableWithContainerWithMultipleAttributes::value)
|
||||
.containsExactly("a", "b");
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -1557,4 +1584,24 @@ class AnnotatedElementUtilsTests {
|
||||
static class ValueAttributeMetaMetaClass {
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface StandardContainerWithMultipleAttributes {
|
||||
|
||||
StandardRepeatableWithContainerWithMultipleAttributes[] value();
|
||||
|
||||
String name() default "";
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(StandardContainerWithMultipleAttributes.class)
|
||||
@interface StandardRepeatableWithContainerWithMultipleAttributes {
|
||||
|
||||
String value() default "";
|
||||
}
|
||||
|
||||
@StandardRepeatableWithContainerWithMultipleAttributes("a")
|
||||
@StandardRepeatableWithContainerWithMultipleAttributes("b")
|
||||
static class StandardRepeatablesWithContainerWithMultipleAttributesTestCase {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -58,24 +58,6 @@ class AttributeMethodsTests {
|
||||
assertThat(getAll(methods)).flatExtracting(Method::getName).containsExactly("intValue", "value");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasOnlyValueAttributeWhenHasOnlyValueAttributeReturnsTrue() {
|
||||
AttributeMethods methods = AttributeMethods.forAnnotationType(ValueOnly.class);
|
||||
assertThat(methods.hasOnlyValueAttribute()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasOnlyValueAttributeWhenHasOnlySingleNonValueAttributeReturnsFalse() {
|
||||
AttributeMethods methods = AttributeMethods.forAnnotationType(NonValueOnly.class);
|
||||
assertThat(methods.hasOnlyValueAttribute()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasOnlyValueAttributeWhenHasOnlyMultipleAttributesIncludingValueReturnsFalse() {
|
||||
AttributeMethods methods = AttributeMethods.forAnnotationType(MultipleAttributes.class);
|
||||
assertThat(methods.hasOnlyValueAttribute()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexOfNameReturnsIndex() {
|
||||
AttributeMethods methods = AttributeMethods.forAnnotationType(MultipleAttributes.class);
|
||||
|
||||
+157
-146
@@ -20,7 +20,9 @@ import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -31,193 +33,175 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
* Tests for {@link RepeatableContainers}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
class RepeatableContainersTests {
|
||||
|
||||
@Test
|
||||
void standardRepeatablesWhenNonRepeatableReturnsNull() {
|
||||
Object[] values = findRepeatedAnnotationValues(
|
||||
RepeatableContainers.standardRepeatables(), WithNonRepeatable.class,
|
||||
NonRepeatable.class);
|
||||
assertThat(values).isNull();
|
||||
@Nested
|
||||
class StandardRepeatableContainersTests {
|
||||
|
||||
@Test
|
||||
void standardRepeatablesWhenNonRepeatableReturnsNull() {
|
||||
Object[] values = findRepeatedAnnotationValues(RepeatableContainers.standardRepeatables(),
|
||||
NonRepeatableTestCase.class, NonRepeatable.class);
|
||||
assertThat(values).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void standardRepeatablesWhenSingleReturnsNull() {
|
||||
Object[] values = findRepeatedAnnotationValues(RepeatableContainers.standardRepeatables(),
|
||||
SingleStandardRepeatableTestCase.class, StandardRepeatable.class);
|
||||
assertThat(values).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void standardRepeatablesWhenContainerButNotRepeatableReturnsNull() {
|
||||
Object[] values = findRepeatedAnnotationValues(RepeatableContainers.standardRepeatables(),
|
||||
ExplicitRepeatablesTestCase.class, ExplicitContainer.class);
|
||||
assertThat(values).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void standardRepeatablesWhenContainerReturnsRepeats() {
|
||||
Object[] values = findRepeatedAnnotationValues(RepeatableContainers.standardRepeatables(),
|
||||
StandardRepeatablesTestCase.class, StandardContainer.class);
|
||||
assertThat(values).containsExactly("a", "b");
|
||||
}
|
||||
|
||||
@Test
|
||||
void standardRepeatablesWithContainerWithMultipleAttributes() {
|
||||
Object[] values = findRepeatedAnnotationValues(RepeatableContainers.standardRepeatables(),
|
||||
StandardRepeatablesWithContainerWithMultipleAttributesTestCase.class,
|
||||
StandardContainerWithMultipleAttributes.class);
|
||||
assertThat(values).containsExactly("a", "b");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void standardRepeatablesWhenSingleReturnsNull() {
|
||||
Object[] values = findRepeatedAnnotationValues(
|
||||
RepeatableContainers.standardRepeatables(),
|
||||
WithSingleStandardRepeatable.class, StandardRepeatable.class);
|
||||
assertThat(values).isNull();
|
||||
}
|
||||
@Nested
|
||||
class ExplicitRepeatableContainerTests {
|
||||
|
||||
@Test
|
||||
void standardRepeatablesWhenContainerReturnsRepeats() {
|
||||
Object[] values = findRepeatedAnnotationValues(
|
||||
RepeatableContainers.standardRepeatables(), WithStandardRepeatables.class,
|
||||
StandardContainer.class);
|
||||
assertThat(values).containsExactly("a", "b");
|
||||
}
|
||||
@Test
|
||||
void ofExplicitWhenNonRepeatableReturnsNull() {
|
||||
Object[] values = findRepeatedAnnotationValues(
|
||||
RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class),
|
||||
NonRepeatableTestCase.class, NonRepeatable.class);
|
||||
assertThat(values).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void standardRepeatablesWhenContainerButNotRepeatableReturnsNull() {
|
||||
Object[] values = findRepeatedAnnotationValues(
|
||||
RepeatableContainers.standardRepeatables(), WithExplicitRepeatables.class,
|
||||
ExplicitContainer.class);
|
||||
assertThat(values).isNull();
|
||||
}
|
||||
@Test
|
||||
void ofExplicitWhenStandardRepeatableContainerReturnsNull() {
|
||||
Object[] values = findRepeatedAnnotationValues(
|
||||
RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class),
|
||||
StandardRepeatablesTestCase.class, StandardContainer.class);
|
||||
assertThat(values).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofExplicitWhenNonRepeatableReturnsNull() {
|
||||
Object[] values = findRepeatedAnnotationValues(
|
||||
RepeatableContainers.of(ExplicitRepeatable.class,
|
||||
ExplicitContainer.class),
|
||||
WithNonRepeatable.class, NonRepeatable.class);
|
||||
assertThat(values).isNull();
|
||||
}
|
||||
@Test
|
||||
void ofExplicitWhenContainerReturnsRepeats() {
|
||||
Object[] values = findRepeatedAnnotationValues(
|
||||
RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class),
|
||||
ExplicitRepeatablesTestCase.class, ExplicitContainer.class);
|
||||
assertThat(values).containsExactly("a", "b");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofExplicitWhenStandardRepeatableContainerReturnsNull() {
|
||||
Object[] values = findRepeatedAnnotationValues(
|
||||
RepeatableContainers.of(ExplicitRepeatable.class,
|
||||
ExplicitContainer.class),
|
||||
WithStandardRepeatables.class, StandardContainer.class);
|
||||
assertThat(values).isNull();
|
||||
}
|
||||
@Test
|
||||
void ofExplicitWhenContainerIsNullDeducesContainer() {
|
||||
Object[] values = findRepeatedAnnotationValues(RepeatableContainers.of(StandardRepeatable.class, null),
|
||||
StandardRepeatablesTestCase.class, StandardContainer.class);
|
||||
assertThat(values).containsExactly("a", "b");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofExplicitWhenContainerReturnsRepeats() {
|
||||
Object[] values = findRepeatedAnnotationValues(
|
||||
RepeatableContainers.of(ExplicitRepeatable.class,
|
||||
ExplicitContainer.class),
|
||||
WithExplicitRepeatables.class, ExplicitContainer.class);
|
||||
assertThat(values).containsExactly("a", "b");
|
||||
}
|
||||
@Test
|
||||
void ofExplicitWhenHasNoValueThrowsException() {
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> RepeatableContainers.of(ExplicitRepeatable.class, InvalidNoValue.class))
|
||||
.withMessageContaining("Invalid declaration of container type [%s] for repeatable annotation [%s]",
|
||||
InvalidNoValue.class.getName(), ExplicitRepeatable.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofExplicitWhenHasNoValueThrowsException() {
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() ->
|
||||
RepeatableContainers.of(ExplicitRepeatable.class, InvalidNoValue.class))
|
||||
.withMessageContaining("Invalid declaration of container type ["
|
||||
+ InvalidNoValue.class.getName()
|
||||
+ "] for repeatable annotation ["
|
||||
+ ExplicitRepeatable.class.getName() + "]");
|
||||
}
|
||||
@Test
|
||||
void ofExplicitWhenValueIsNotArrayThrowsException() {
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> RepeatableContainers.of(ExplicitRepeatable.class, InvalidNotArray.class))
|
||||
.withMessage("Container type [%s] must declare a 'value' attribute for an array of type [%s]",
|
||||
InvalidNotArray.class.getName(), ExplicitRepeatable.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofExplicitWhenValueIsNotArrayThrowsException() {
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() ->
|
||||
RepeatableContainers.of(ExplicitRepeatable.class, InvalidNotArray.class))
|
||||
.withMessage("Container type ["
|
||||
+ InvalidNotArray.class.getName()
|
||||
+ "] must declare a 'value' attribute for an array of type ["
|
||||
+ ExplicitRepeatable.class.getName() + "]");
|
||||
}
|
||||
@Test
|
||||
void ofExplicitWhenValueIsArrayOfWrongTypeThrowsException() {
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> RepeatableContainers.of(ExplicitRepeatable.class, InvalidWrongArrayType.class))
|
||||
.withMessage("Container type [%s] must declare a 'value' attribute for an array of type [%s]",
|
||||
InvalidWrongArrayType.class.getName(), ExplicitRepeatable.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofExplicitWhenValueIsArrayOfWrongTypeThrowsException() {
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() ->
|
||||
RepeatableContainers.of(ExplicitRepeatable.class, InvalidWrongArrayType.class))
|
||||
.withMessage("Container type ["
|
||||
+ InvalidWrongArrayType.class.getName()
|
||||
+ "] must declare a 'value' attribute for an array of type ["
|
||||
+ ExplicitRepeatable.class.getName() + "]");
|
||||
}
|
||||
@Test
|
||||
void ofExplicitWhenAnnotationIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> RepeatableContainers.of(null, null))
|
||||
.withMessage("Repeatable must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofExplicitWhenAnnotationIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
||||
RepeatableContainers.of(null, null))
|
||||
.withMessage("Repeatable must not be null");
|
||||
}
|
||||
@Test
|
||||
void ofExplicitWhenContainerIsNullAndNotRepeatableThrowsException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> RepeatableContainers.of(ExplicitRepeatable.class, null))
|
||||
.withMessage("Annotation type must be a repeatable annotation: failed to resolve container type for %s",
|
||||
ExplicitRepeatable.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofExplicitWhenContainerIsNullDeducesContainer() {
|
||||
Object[] values = findRepeatedAnnotationValues(
|
||||
RepeatableContainers.of(StandardRepeatable.class, null),
|
||||
WithStandardRepeatables.class, StandardContainer.class);
|
||||
assertThat(values).containsExactly("a", "b");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofExplicitWhenContainerIsNullAndNotRepeatableThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
||||
RepeatableContainers.of(ExplicitRepeatable.class, null))
|
||||
.withMessage("Annotation type must be a repeatable annotation: " +
|
||||
"failed to resolve container type for " +
|
||||
ExplicitRepeatable.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void standardAndExplicitReturnsRepeats() {
|
||||
RepeatableContainers repeatableContainers = RepeatableContainers.standardRepeatables().and(
|
||||
ExplicitContainer.class, ExplicitRepeatable.class);
|
||||
assertThat(findRepeatedAnnotationValues(repeatableContainers,
|
||||
WithStandardRepeatables.class, StandardContainer.class)).containsExactly(
|
||||
"a", "b");
|
||||
assertThat(findRepeatedAnnotationValues(repeatableContainers,
|
||||
WithExplicitRepeatables.class, ExplicitContainer.class)).containsExactly(
|
||||
"a", "b");
|
||||
RepeatableContainers repeatableContainers = RepeatableContainers.standardRepeatables()
|
||||
.and(ExplicitContainer.class, ExplicitRepeatable.class);
|
||||
assertThat(findRepeatedAnnotationValues(repeatableContainers, StandardRepeatablesTestCase.class, StandardContainer.class))
|
||||
.containsExactly("a", "b");
|
||||
assertThat(findRepeatedAnnotationValues(repeatableContainers, ExplicitRepeatablesTestCase.class, ExplicitContainer.class))
|
||||
.containsExactly("a", "b");
|
||||
}
|
||||
|
||||
@Test
|
||||
void noneAlwaysReturnsNull() {
|
||||
Object[] values = findRepeatedAnnotationValues(
|
||||
RepeatableContainers.none(), WithStandardRepeatables.class,
|
||||
StandardContainer.class);
|
||||
Object[] values = findRepeatedAnnotationValues(RepeatableContainers.none(), StandardRepeatablesTestCase.class,
|
||||
StandardContainer.class);
|
||||
assertThat(values).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void equalsAndHashcode() {
|
||||
RepeatableContainers c1 = RepeatableContainers.of(ExplicitRepeatable.class,
|
||||
ExplicitContainer.class);
|
||||
RepeatableContainers c2 = RepeatableContainers.of(ExplicitRepeatable.class,
|
||||
ExplicitContainer.class);
|
||||
RepeatableContainers c1 = RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class);
|
||||
RepeatableContainers c2 = RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class);
|
||||
RepeatableContainers c3 = RepeatableContainers.standardRepeatables();
|
||||
RepeatableContainers c4 = RepeatableContainers.standardRepeatables().and(
|
||||
ExplicitContainer.class, ExplicitRepeatable.class);
|
||||
assertThat(c1.hashCode()).isEqualTo(c2.hashCode());
|
||||
RepeatableContainers c4 = RepeatableContainers.standardRepeatables().and(ExplicitContainer.class, ExplicitRepeatable.class);
|
||||
assertThat(c1).hasSameHashCodeAs(c2);
|
||||
assertThat(c1).isEqualTo(c1).isEqualTo(c2);
|
||||
assertThat(c1).isNotEqualTo(c3).isNotEqualTo(c4);
|
||||
}
|
||||
|
||||
private Object[] findRepeatedAnnotationValues(RepeatableContainers containers,
|
||||
|
||||
private static Object[] findRepeatedAnnotationValues(RepeatableContainers containers,
|
||||
Class<?> element, Class<? extends Annotation> annotationType) {
|
||||
Annotation[] annotations = containers.findRepeatedAnnotations(
|
||||
element.getAnnotation(annotationType));
|
||||
Annotation[] annotations = containers.findRepeatedAnnotations(element.getAnnotation(annotationType));
|
||||
return extractValues(annotations);
|
||||
}
|
||||
|
||||
private Object[] extractValues(Annotation[] annotations) {
|
||||
try {
|
||||
if (annotations == null) {
|
||||
return null;
|
||||
}
|
||||
Object[] result = new String[annotations.length];
|
||||
for (int i = 0; i < annotations.length; i++) {
|
||||
result[i] = annotations[i].annotationType().getMethod("value").invoke(
|
||||
annotations[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
private static Object[] extractValues(Annotation[] annotations) {
|
||||
if (annotations == null) {
|
||||
return null;
|
||||
}
|
||||
return Arrays.stream(annotations).map(AnnotationUtils::getValue).toArray(Object[]::new);
|
||||
}
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface NonRepeatable {
|
||||
|
||||
String value() default "";
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(StandardContainer.class)
|
||||
@interface StandardRepeatable {
|
||||
|
||||
String value() default "";
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface StandardContainer {
|
||||
|
||||
@@ -225,7 +209,8 @@ class RepeatableContainersTests {
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ExplicitRepeatable {
|
||||
@Repeatable(StandardContainer.class)
|
||||
@interface StandardRepeatable {
|
||||
|
||||
String value() default "";
|
||||
}
|
||||
@@ -236,6 +221,12 @@ class RepeatableContainersTests {
|
||||
ExplicitRepeatable[] value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ExplicitRepeatable {
|
||||
|
||||
String value() default "";
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface InvalidNoValue {
|
||||
}
|
||||
@@ -253,20 +244,40 @@ class RepeatableContainersTests {
|
||||
}
|
||||
|
||||
@NonRepeatable("a")
|
||||
static class WithNonRepeatable {
|
||||
static class NonRepeatableTestCase {
|
||||
}
|
||||
|
||||
@StandardRepeatable("a")
|
||||
static class WithSingleStandardRepeatable {
|
||||
static class SingleStandardRepeatableTestCase {
|
||||
}
|
||||
|
||||
@StandardRepeatable("a")
|
||||
@StandardRepeatable("b")
|
||||
static class WithStandardRepeatables {
|
||||
static class StandardRepeatablesTestCase {
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface StandardContainerWithMultipleAttributes {
|
||||
|
||||
StandardRepeatableWithContainerWithMultipleAttributes[] value();
|
||||
|
||||
String name() default "";
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(StandardContainerWithMultipleAttributes.class)
|
||||
@interface StandardRepeatableWithContainerWithMultipleAttributes {
|
||||
|
||||
String value() default "";
|
||||
}
|
||||
|
||||
@StandardRepeatableWithContainerWithMultipleAttributes("a")
|
||||
@StandardRepeatableWithContainerWithMultipleAttributes("b")
|
||||
static class StandardRepeatablesWithContainerWithMultipleAttributesTestCase {
|
||||
}
|
||||
|
||||
@ExplicitContainer({ @ExplicitRepeatable("a"), @ExplicitRepeatable("b") })
|
||||
static class WithExplicitRepeatables {
|
||||
static class ExplicitRepeatablesTestCase {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -251,32 +251,28 @@ class ObjectUtilsTests {
|
||||
@Deprecated
|
||||
void hashCodeWithDouble() {
|
||||
double dbl = 9830.43;
|
||||
int expected = (new Double(dbl)).hashCode();
|
||||
assertThat(ObjectUtils.hashCode(dbl)).isEqualTo(expected);
|
||||
assertThat(ObjectUtils.hashCode(dbl)).isEqualTo(Double.hashCode(dbl));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Deprecated
|
||||
void hashCodeWithFloat() {
|
||||
float flt = 34.8f;
|
||||
int expected = (Float.valueOf(flt)).hashCode();
|
||||
assertThat(ObjectUtils.hashCode(flt)).isEqualTo(expected);
|
||||
assertThat(ObjectUtils.hashCode(flt)).isEqualTo(Float.hashCode(flt));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Deprecated
|
||||
void hashCodeWithLong() {
|
||||
long lng = 883L;
|
||||
int expected = (Long.valueOf(lng)).hashCode();
|
||||
assertThat(ObjectUtils.hashCode(lng)).isEqualTo(expected);
|
||||
assertThat(ObjectUtils.hashCode(lng)).isEqualTo(Long.hashCode(lng));
|
||||
}
|
||||
|
||||
@Test
|
||||
void identityToString() {
|
||||
Object obj = new Object();
|
||||
String expected = obj.getClass().getName() + "@" + ObjectUtils.getIdentityHexString(obj);
|
||||
String actual = ObjectUtils.identityToString(obj);
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
assertThat(ObjectUtils.identityToString(obj)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -732,7 +728,7 @@ class ObjectUtilsTests {
|
||||
|
||||
@Test
|
||||
void nullSafeToStringWithObjectArray() {
|
||||
Object[] array = {"Han", Long.valueOf(43)};
|
||||
Object[] array = {"Han", 43};
|
||||
assertThat(ObjectUtils.nullSafeToString(array)).isEqualTo("{Han, 43}");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,8 +33,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link StreamUtils}.
|
||||
@@ -57,53 +55,47 @@ class StreamUtilsTests {
|
||||
|
||||
@Test
|
||||
void copyToByteArray() throws Exception {
|
||||
InputStream inputStream = spy(new ByteArrayInputStream(bytes));
|
||||
InputStream inputStream = new ByteArrayInputStream(bytes);
|
||||
byte[] actual = StreamUtils.copyToByteArray(inputStream);
|
||||
assertThat(actual).isEqualTo(bytes);
|
||||
verify(inputStream, never()).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void copyToString() throws Exception {
|
||||
Charset charset = Charset.defaultCharset();
|
||||
InputStream inputStream = spy(new ByteArrayInputStream(string.getBytes(charset)));
|
||||
InputStream inputStream = new ByteArrayInputStream(string.getBytes(charset));
|
||||
String actual = StreamUtils.copyToString(inputStream, charset);
|
||||
assertThat(actual).isEqualTo(string);
|
||||
verify(inputStream, never()).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void copyBytes() throws Exception {
|
||||
ByteArrayOutputStream out = spy(new ByteArrayOutputStream());
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamUtils.copy(bytes, out);
|
||||
assertThat(out.toByteArray()).isEqualTo(bytes);
|
||||
verify(out, never()).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void copyString() throws Exception {
|
||||
Charset charset = Charset.defaultCharset();
|
||||
ByteArrayOutputStream out = spy(new ByteArrayOutputStream());
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamUtils.copy(string, charset, out);
|
||||
assertThat(out.toByteArray()).isEqualTo(string.getBytes(charset));
|
||||
verify(out, never()).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void copyStream() throws Exception {
|
||||
ByteArrayOutputStream out = spy(new ByteArrayOutputStream());
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamUtils.copy(new ByteArrayInputStream(bytes), out);
|
||||
assertThat(out.toByteArray()).isEqualTo(bytes);
|
||||
verify(out, never()).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void copyRange() throws Exception {
|
||||
ByteArrayOutputStream out = spy(new ByteArrayOutputStream());
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamUtils.copyRange(new ByteArrayInputStream(bytes), out, 0, 100);
|
||||
byte[] range = Arrays.copyOfRange(bytes, 0, 101);
|
||||
assertThat(out.toByteArray()).isEqualTo(range);
|
||||
verify(out, never()).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+37
-13
@@ -22,6 +22,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
@@ -46,10 +47,15 @@ import org.springframework.util.Assert;
|
||||
* Represents the invocation of a constructor. Either a constructor on a regular type or
|
||||
* construction of an array. When an array is constructed, an initializer can be specified.
|
||||
*
|
||||
* <p>Examples:<br>
|
||||
* new String('hello world')<br>
|
||||
* new int[]{1,2,3,4}<br>
|
||||
* new int[3] new int[3]{1,2,3}
|
||||
* <h4>Examples</h4>
|
||||
* <ul>
|
||||
* <li><code>new example.Foo()</code></li>
|
||||
* <li><code>new String('hello world')</code></li>
|
||||
* <li><code>new int[] {1,2,3,4}</code></li>
|
||||
* <li><code>new String[] {'abc','xyz'}</code></li>
|
||||
* <li><code>new int[5]</code></li>
|
||||
* <li><code>new int[3][4]</code></li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
@@ -68,7 +74,7 @@ public class ConstructorReference extends SpelNodeImpl {
|
||||
private final boolean isArrayConstructor;
|
||||
|
||||
@Nullable
|
||||
private SpelNodeImpl[] dimensions;
|
||||
private final SpelNodeImpl[] dimensions;
|
||||
|
||||
// TODO is this caching safe - passing the expression around will mean this executor is also being passed around
|
||||
/** The cached executor that may be reused on subsequent evaluations. */
|
||||
@@ -83,6 +89,7 @@ public class ConstructorReference extends SpelNodeImpl {
|
||||
public ConstructorReference(int startPos, int endPos, SpelNodeImpl... arguments) {
|
||||
super(startPos, endPos, arguments);
|
||||
this.isArrayConstructor = false;
|
||||
this.dimensions = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,16 +221,33 @@ public class ConstructorReference extends SpelNodeImpl {
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
StringBuilder sb = new StringBuilder("new ");
|
||||
int index = 0;
|
||||
sb.append(getChild(index++).toStringAST());
|
||||
sb.append('(');
|
||||
for (int i = index; i < getChildCount(); i++) {
|
||||
if (i > index) {
|
||||
sb.append(',');
|
||||
sb.append(getChild(0).toStringAST()); // constructor or array type
|
||||
|
||||
// Arrays
|
||||
if (this.isArrayConstructor) {
|
||||
if (hasInitializer()) {
|
||||
// new int[] {1, 2, 3, 4, 5}, etc.
|
||||
InlineList initializer = (InlineList) getChild(1);
|
||||
sb.append("[] ").append(initializer.toStringAST());
|
||||
}
|
||||
else {
|
||||
// new int[3], new java.lang.String[3][4], etc.
|
||||
for (SpelNodeImpl dimension : this.dimensions) {
|
||||
sb.append('[').append(dimension.toStringAST()).append(']');
|
||||
}
|
||||
}
|
||||
sb.append(getChild(i).toStringAST());
|
||||
}
|
||||
sb.append(')');
|
||||
// Constructors
|
||||
else {
|
||||
// new String('hello'), new org.example.Person('Jane', 32), etc.
|
||||
StringJoiner sj = new StringJoiner(",", "(", ")");
|
||||
int count = getChildCount();
|
||||
for (int i = 1; i < count; i++) {
|
||||
sj.add(getChild(i).toStringAST());
|
||||
}
|
||||
sb.append(sj.toString());
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
+17
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,6 +26,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public class StringLiteral extends Literal {
|
||||
@@ -36,9 +37,19 @@ public class StringLiteral extends Literal {
|
||||
public StringLiteral(String payload, int startPos, int endPos, String value) {
|
||||
super(payload, startPos, endPos);
|
||||
|
||||
// The original enclosing quote character for the string literal: ' or ".
|
||||
char quoteCharacter = value.charAt(0);
|
||||
|
||||
// Remove enclosing quotes
|
||||
String valueWithinQuotes = value.substring(1, value.length() - 1);
|
||||
valueWithinQuotes = StringUtils.replace(valueWithinQuotes, "''", "'");
|
||||
valueWithinQuotes = StringUtils.replace(valueWithinQuotes, "\"\"", "\"");
|
||||
|
||||
// Replace escaped internal quote characters
|
||||
if (quoteCharacter == '\'') {
|
||||
valueWithinQuotes = StringUtils.replace(valueWithinQuotes, "''", "'");
|
||||
}
|
||||
else {
|
||||
valueWithinQuotes = StringUtils.replace(valueWithinQuotes, "\"\"", "\"");
|
||||
}
|
||||
|
||||
this.value = new TypedValue(valueWithinQuotes);
|
||||
this.exitTypeDescriptor = "Ljava/lang/String";
|
||||
@@ -52,7 +63,9 @@ public class StringLiteral extends Literal {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "'" + getLiteralValue().getValue() + "'";
|
||||
String ast = String.valueOf(getLiteralValue().getValue());
|
||||
ast = StringUtils.replace(ast, "'", "''");
|
||||
return "'" + ast + "'";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+47
@@ -364,6 +364,53 @@ class EvaluationTests extends AbstractExpressionTests {
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
class StringLiterals {
|
||||
|
||||
@Test
|
||||
void insideSingleQuotes() {
|
||||
evaluate("'hello'", "hello", String.class);
|
||||
evaluate("'hello world'", "hello world", String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void insideDoubleQuotes() {
|
||||
evaluate("\"hello\"", "hello", String.class);
|
||||
evaluate("\"hello world\"", "hello world", String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleQuotesInsideSingleQuotes() {
|
||||
evaluate("'Tony''s Pizza'", "Tony's Pizza", String.class);
|
||||
evaluate("'big ''''pizza'''' parlor'", "big ''pizza'' parlor", String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void doubleQuotesInsideDoubleQuotes() {
|
||||
evaluate("\"big \"\"pizza\"\" parlor\"", "big \"pizza\" parlor", String.class);
|
||||
evaluate("\"big \"\"\"\"pizza\"\"\"\" parlor\"", "big \"\"pizza\"\" parlor", String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleQuotesInsideDoubleQuotes() {
|
||||
evaluate("\"Tony's Pizza\"", "Tony's Pizza", String.class);
|
||||
evaluate("\"big ''pizza'' parlor\"", "big ''pizza'' parlor", String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void doubleQuotesInsideSingleQuotes() {
|
||||
evaluate("'big \"pizza\" parlor'", "big \"pizza\" parlor", String.class);
|
||||
evaluate("'two double \"\" quotes'", "two double \"\" quotes", String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void inCompoundExpressions() {
|
||||
evaluate("'123''4' == '123''4'", true, Boolean.class);
|
||||
evaluate("\"123\"\"4\" == \"123\"\"4\"", true, Boolean.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
class RelationalOperatorTests {
|
||||
|
||||
|
||||
+41
-23
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -29,52 +29,70 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
/**
|
||||
* @author Andy Clement
|
||||
*/
|
||||
public class LiteralExpressionTests {
|
||||
class LiteralExpressionTests {
|
||||
|
||||
private final LiteralExpression lEx = new LiteralExpression("somevalue");
|
||||
|
||||
|
||||
@Test
|
||||
public void testGetValue() throws Exception {
|
||||
LiteralExpression lEx = new LiteralExpression("somevalue");
|
||||
assertThat(lEx.getValue()).isInstanceOf(String.class).isEqualTo("somevalue");
|
||||
assertThat(lEx.getValue(String.class)).isInstanceOf(String.class).isEqualTo("somevalue");
|
||||
void getValue() throws Exception {
|
||||
assertThat(lEx.getValue()).isEqualTo("somevalue");
|
||||
assertThat(lEx.getValue(String.class)).isEqualTo("somevalue");
|
||||
assertThat(lEx.getValue(new Rooty())).isEqualTo("somevalue");
|
||||
assertThat(lEx.getValue(new Rooty(), String.class)).isEqualTo("somevalue");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getValueWithSuppliedEvaluationContext() throws Exception {
|
||||
EvaluationContext ctx = new StandardEvaluationContext();
|
||||
assertThat(lEx.getValue(ctx)).isInstanceOf(String.class).isEqualTo("somevalue");
|
||||
assertThat(lEx.getValue(ctx, String.class)).isInstanceOf(String.class).isEqualTo("somevalue");
|
||||
assertThat(lEx.getValue(new Rooty())).isInstanceOf(String.class).isEqualTo("somevalue");
|
||||
assertThat(lEx.getValue(new Rooty(), String.class)).isInstanceOf(String.class).isEqualTo("somevalue");
|
||||
assertThat(lEx.getValue(ctx, new Rooty())).isInstanceOf(String.class).isEqualTo("somevalue");
|
||||
assertThat(lEx.getValue(ctx, new Rooty(),String.class)).isInstanceOf(String.class).isEqualTo("somevalue");
|
||||
assertThat(lEx.getValue(ctx)).isEqualTo("somevalue");
|
||||
assertThat(lEx.getValue(ctx, String.class)).isEqualTo("somevalue");
|
||||
assertThat(lEx.getValue(ctx, new Rooty())).isEqualTo("somevalue");
|
||||
assertThat(lEx.getValue(ctx, new Rooty(), String.class)).isEqualTo("somevalue");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getExpressionString() {
|
||||
assertThat(lEx.getExpressionString()).isEqualTo("somevalue");
|
||||
}
|
||||
|
||||
@Test
|
||||
void isWritable() throws Exception {
|
||||
assertThat(lEx.isWritable(new StandardEvaluationContext())).isFalse();
|
||||
assertThat(lEx.isWritable(new Rooty())).isFalse();
|
||||
assertThat(lEx.isWritable(new StandardEvaluationContext(), new Rooty())).isFalse();
|
||||
}
|
||||
|
||||
static class Rooty {}
|
||||
|
||||
@Test
|
||||
public void testSetValue() {
|
||||
assertThatExceptionOfType(EvaluationException.class).isThrownBy(() ->
|
||||
new LiteralExpression("somevalue").setValue(new StandardEvaluationContext(), "flibble"))
|
||||
void setValue() {
|
||||
assertThatExceptionOfType(EvaluationException.class)
|
||||
.isThrownBy(() -> lEx.setValue(new StandardEvaluationContext(), "flibble"))
|
||||
.satisfies(ex -> assertThat(ex.getExpressionString()).isEqualTo("somevalue"));
|
||||
assertThatExceptionOfType(EvaluationException.class).isThrownBy(() ->
|
||||
new LiteralExpression("somevalue").setValue(new Rooty(), "flibble"))
|
||||
assertThatExceptionOfType(EvaluationException.class)
|
||||
.isThrownBy(() -> lEx.setValue(new Rooty(), "flibble"))
|
||||
.satisfies(ex -> assertThat(ex.getExpressionString()).isEqualTo("somevalue"));
|
||||
assertThatExceptionOfType(EvaluationException.class).isThrownBy(() ->
|
||||
new LiteralExpression("somevalue").setValue(new StandardEvaluationContext(), new Rooty(), "flibble"))
|
||||
assertThatExceptionOfType(EvaluationException.class)
|
||||
.isThrownBy(() -> lEx.setValue(new StandardEvaluationContext(), new Rooty(), "flibble"))
|
||||
.satisfies(ex -> assertThat(ex.getExpressionString()).isEqualTo("somevalue"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValueType() throws Exception {
|
||||
LiteralExpression lEx = new LiteralExpression("somevalue");
|
||||
void getValueType() throws Exception {
|
||||
assertThat(lEx.getValueType()).isEqualTo(String.class);
|
||||
assertThat(lEx.getValueType(new StandardEvaluationContext())).isEqualTo(String.class);
|
||||
assertThat(lEx.getValueType(new Rooty())).isEqualTo(String.class);
|
||||
assertThat(lEx.getValueType(new StandardEvaluationContext(), new Rooty())).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getValueTypeDescriptor() throws Exception {
|
||||
assertThat(lEx.getValueTypeDescriptor().getType()).isEqualTo(String.class);
|
||||
assertThat(lEx.getValueTypeDescriptor(new StandardEvaluationContext()).getType()).isEqualTo(String.class);
|
||||
assertThat(lEx.getValueTypeDescriptor(new Rooty()).getType()).isEqualTo(String.class);
|
||||
assertThat(lEx.getValueTypeDescriptor(new StandardEvaluationContext(), new Rooty()).getType()).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
|
||||
static class Rooty {}
|
||||
|
||||
}
|
||||
|
||||
+485
-379
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.expression.spel;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
@@ -37,413 +39,517 @@ class ParsingTests {
|
||||
private final SpelExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
|
||||
// literals
|
||||
@Test
|
||||
void literalBoolean01() {
|
||||
parseCheck("false");
|
||||
@Nested
|
||||
class Miscellaneous {
|
||||
|
||||
@Test
|
||||
void literalNull() {
|
||||
parseCheck("null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalDate01() {
|
||||
parseCheck("date('1974/08/24')");
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalDate02() {
|
||||
parseCheck("date('19740824T131030','yyyyMMddTHHmmss')");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mixedOperators() {
|
||||
parseCheck("true and 5>3", "(true and (5 > 3))");
|
||||
}
|
||||
|
||||
@Test
|
||||
void assignmentToVariables() {
|
||||
parseCheck("#var1='value1'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectionProcessorsCountStringArray() {
|
||||
parseCheck("new String[] {'abc','def','xyz'}.count()");
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectionProcessorsCountIntArray() {
|
||||
parseCheck("new int[] {1,2,3}.count()");
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectionProcessorsMax() {
|
||||
parseCheck("new int[] {1,2,3}.max()");
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectionProcessorsMin() {
|
||||
parseCheck("new int[] {1,2,3}.min()");
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectionProcessorsAverage() {
|
||||
parseCheck("new int[] {1,2,3}.average()");
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectionProcessorsSort() {
|
||||
parseCheck("new int[] {3,2,1}.sort()");
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectionProcessorsNonNull() {
|
||||
parseCheck("{'a','b',null,'d',null}.nonNull()");
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectionProcessorsDistinct() {
|
||||
parseCheck("{'a','b','a','d','e'}.distinct()");
|
||||
}
|
||||
|
||||
@Disabled("Unsupported syntax/feature")
|
||||
@Test
|
||||
void lambdaMax() {
|
||||
parseCheck("(#max = {|x,y| $x > $y ? $x : $y }; #max(5,25))",
|
||||
"(#max={|x,y| ($x > $y) ? $x : $y };#max(5,25))");
|
||||
}
|
||||
|
||||
@Disabled("Unsupported syntax/feature")
|
||||
@Test
|
||||
void lambdaFactorial() {
|
||||
parseCheck("(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #fact(5))",
|
||||
"(#fact={|n| ($n <= 1) ? 1 : ($n * #fact(($n - 1))) };#fact(5))");
|
||||
}
|
||||
|
||||
@Disabled("Unsupported syntax/feature")
|
||||
@Test
|
||||
void projection() {
|
||||
parseCheck("{1,2,3,4,5,6,7,8,9,10}.!{#isEven()}");
|
||||
}
|
||||
|
||||
@Disabled("Unsupported syntax/feature")
|
||||
@Test
|
||||
void selection() {
|
||||
parseCheck("{1,2,3,4,5,6,7,8,9,10}.?{#isEven(#this) == 'y'}",
|
||||
"{1,2,3,4,5,6,7,8,9,10}.?{(#isEven(#this) == 'y')}");
|
||||
}
|
||||
|
||||
@Disabled("Unsupported syntax/feature")
|
||||
@Test
|
||||
void selectionFirst() {
|
||||
parseCheck("{1,2,3,4,5,6,7,8,9,10}.^{#isEven(#this) == 'y'}",
|
||||
"{1,2,3,4,5,6,7,8,9,10}.^{(#isEven(#this) == 'y')}");
|
||||
}
|
||||
|
||||
@Disabled("Unsupported syntax/feature")
|
||||
@Test
|
||||
void selectionLast() {
|
||||
parseCheck("{1,2,3,4,5,6,7,8,9,10}.${#isEven(#this) == 'y'}",
|
||||
"{1,2,3,4,5,6,7,8,9,10}.${(#isEven(#this) == 'y')}");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalLong01() {
|
||||
parseCheck("37L", "37");
|
||||
@Nested
|
||||
class LiteralBooleans {
|
||||
|
||||
@Test
|
||||
void literalBooleanFalse() {
|
||||
parseCheck("false");
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalBooleanTrue() {
|
||||
parseCheck("true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalBooleanNotTrue() {
|
||||
parseCheck("!true");
|
||||
parseCheck("not true", "!true");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalBoolean02() {
|
||||
parseCheck("true");
|
||||
@Nested
|
||||
class LiteralNumbers {
|
||||
|
||||
@Test
|
||||
void literalLong() {
|
||||
parseCheck("37L", "37");
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalIntegers() {
|
||||
parseCheck("1");
|
||||
parseCheck("1415");
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalReal() {
|
||||
parseCheck("6.0221415E+23", "6.0221415E23");
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalHex() {
|
||||
parseCheck("0x7FFFFFFF", "2147483647");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalBoolean03() {
|
||||
parseCheck("!true");
|
||||
@Nested
|
||||
class LiteralStrings {
|
||||
|
||||
@Test
|
||||
void insideSingleQuotes() {
|
||||
parseCheck("'hello'");
|
||||
parseCheck("'hello world'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void insideDoubleQuotes() {
|
||||
parseCheck("\"hello\"", "'hello'");
|
||||
parseCheck("\"hello world\"", "'hello world'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleQuotesInsideSingleQuotes() {
|
||||
parseCheck("'Tony''s Pizza'");
|
||||
parseCheck("'big ''''pizza'''' parlor'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void doubleQuotesInsideDoubleQuotes() {
|
||||
parseCheck("\"big \"\"pizza\"\" parlor\"", "'big \"pizza\" parlor'");
|
||||
parseCheck("\"big \"\"\"\"pizza\"\"\"\" parlor\"", "'big \"\"pizza\"\" parlor'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleQuotesInsideDoubleQuotes() {
|
||||
parseCheck("\"Tony's Pizza\"", "'Tony''s Pizza'");
|
||||
parseCheck("\"big ''pizza'' parlor\"", "'big ''''pizza'''' parlor'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void doubleQuotesInsideSingleQuotes() {
|
||||
parseCheck("'big \"pizza\" parlor'");
|
||||
parseCheck("'two double \"\" quotes'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inCompoundExpressions() {
|
||||
parseCheck("'123''4' == '123''4'", "('123''4' == '123''4')");
|
||||
parseCheck("('123''4'=='123''4')", "('123''4' == '123''4')");
|
||||
parseCheck("\"123\"\"4\" == \"123\"\"4\"", "('123\"4' == '123\"4')");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalInteger01() {
|
||||
parseCheck("1");
|
||||
@Nested
|
||||
class BooleanOperators {
|
||||
|
||||
@Test
|
||||
void booleanOperatorsOr01() {
|
||||
parseCheck("false or false", "(false or false)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void booleanOperatorsOr02() {
|
||||
parseCheck("false or true", "(false or true)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void booleanOperatorsOr03() {
|
||||
parseCheck("true or false", "(true or false)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void booleanOperatorsOr04() {
|
||||
parseCheck("true or false", "(true or false)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void booleanOperatorsMix() {
|
||||
parseCheck("false or true and false", "(false or (true and false))");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalInteger02() {
|
||||
parseCheck("1415");
|
||||
@Nested
|
||||
class RelationalOperators {
|
||||
|
||||
@Test
|
||||
void relOperatorsGT() {
|
||||
parseCheck("3>6", "(3 > 6)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void relOperatorsLT() {
|
||||
parseCheck("3<6", "(3 < 6)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void relOperatorsLE() {
|
||||
parseCheck("3<=6", "(3 <= 6)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void relOperatorsGE01() {
|
||||
parseCheck("3>=6", "(3 >= 6)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void relOperatorsGE02() {
|
||||
parseCheck("3>=3", "(3 >= 3)");
|
||||
}
|
||||
|
||||
@Disabled("Unsupported syntax/feature")
|
||||
@Test
|
||||
void relOperatorsIn() {
|
||||
parseCheck("3 in {1,2,3,4,5}", "(3 in {1,2,3,4,5})");
|
||||
}
|
||||
|
||||
@Test
|
||||
void relOperatorsBetweenNumbers() {
|
||||
parseCheck("1 between {1, 5}", "(1 between {1,5})");
|
||||
}
|
||||
|
||||
@Test
|
||||
void relOperatorsBetweenStrings() {
|
||||
parseCheck("'efg' between {'abc', 'xyz'}", "('efg' between {'abc','xyz'})");
|
||||
}
|
||||
|
||||
@Test
|
||||
void relOperatorsInstanceOfInt() {
|
||||
parseCheck("'xyz' instanceof int", "('xyz' instanceof int)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void relOperatorsInstanceOfList() {
|
||||
parseCheck("{1, 2, 3, 4, 5} instanceof List", "({1,2,3,4,5} instanceof List)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void relOperatorsMatches() {
|
||||
parseCheck("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'", "('5.0067' matches '^-?\\d+(\\.\\d{2})?$')");
|
||||
parseCheck("'5.00' matches '^-?\\d+(\\.\\d{2})?$'", "('5.00' matches '^-?\\d+(\\.\\d{2})?$')");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalString01() {
|
||||
parseCheck("'hello'");
|
||||
@Nested
|
||||
class MathematicalOperators {
|
||||
|
||||
@Test
|
||||
void mathOperatorsAddIntegers() {
|
||||
parseCheck("2+4", "(2 + 4)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mathOperatorsAddStrings() {
|
||||
parseCheck("'a'+'b'", "('a' + 'b')");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mathOperatorsAddMultipleStrings() {
|
||||
parseCheck("'hello'+' '+'world'", "(('hello' + ' ') + 'world')");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mathOperatorsSubtract() {
|
||||
parseCheck("5-4", "(5 - 4)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mathOperatorsMultiply() {
|
||||
parseCheck("7*4", "(7 * 4)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mathOperatorsDivide() {
|
||||
parseCheck("8/4", "(8 / 4)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mathOperatorModulus() {
|
||||
parseCheck("7 % 4", "(7 % 4)");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalString02() {
|
||||
parseCheck("'joe bloggs'");
|
||||
@Nested
|
||||
class References {
|
||||
|
||||
@Test
|
||||
void references() {
|
||||
parseCheck("@foo");
|
||||
parseCheck("@'foo.bar'");
|
||||
parseCheck("@\"foo.bar.goo\"" , "@'foo.bar.goo'");
|
||||
parseCheck("@$$foo");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalString03() {
|
||||
parseCheck("'Tony''s Pizza'", "'Tony's Pizza'");
|
||||
@Nested
|
||||
class Properties {
|
||||
|
||||
@Test
|
||||
void propertiesSingle() {
|
||||
parseCheck("name");
|
||||
}
|
||||
|
||||
@Test
|
||||
void propertiesDouble() {
|
||||
parseCheck("placeofbirth.CitY");
|
||||
}
|
||||
|
||||
@Test
|
||||
void propertiesMultiple() {
|
||||
parseCheck("a.b.c.d.e");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalReal01() {
|
||||
parseCheck("6.0221415E+23", "6.0221415E23");
|
||||
@Nested
|
||||
class InlineCollections {
|
||||
|
||||
@Test
|
||||
void inlineListOfIntegers() {
|
||||
parseCheck("{1,2,3,4}");
|
||||
parseCheck("{1, 2, 3, 4, 5}", "{1,2,3,4,5}");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inlineListOfStrings() {
|
||||
parseCheck("{'abc','xyz'}", "{'abc','xyz'}");
|
||||
parseCheck("{\"abc\", 'xyz'}", "{'abc','xyz'}");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inlineMapStringToObject() {
|
||||
parseCheck("{'key1':'Value 1','today':DateTime.Today}");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inlineMapIntegerToString() {
|
||||
parseCheck("{1:'January',2:'February',3:'March'}");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalHex01() {
|
||||
parseCheck("0x7FFFFFFF", "2147483647");
|
||||
@Nested
|
||||
class MethodsConstructorsAndArrays {
|
||||
|
||||
@Test
|
||||
void methods() {
|
||||
parseCheck("echo()");
|
||||
parseCheck("echo(12)");
|
||||
parseCheck("echo(name)");
|
||||
parseCheck("echo('Jane')");
|
||||
parseCheck("echo('Jane',32)");
|
||||
parseCheck("echo('Jane', 32)", "echo('Jane',32)");
|
||||
parseCheck("age.doubleItAndAdd(12)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructorWithNoArguments() {
|
||||
parseCheck("new Foo()");
|
||||
parseCheck("new example.Foo()");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructorWithOneArgument() {
|
||||
parseCheck("new String('hello')");
|
||||
parseCheck("new String( 'hello' )", "new String('hello')");
|
||||
parseCheck("new String(\"hello\" )", "new String('hello')");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructorWithMultipleArguments() {
|
||||
parseCheck("new example.Person('Jane',32,true)");
|
||||
parseCheck("new example.Person('Jane', 32, true)", "new example.Person('Jane',32,true)");
|
||||
parseCheck("new example.Person('Jane', 2 * 16, true)", "new example.Person('Jane',(2 * 16),true)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void arrayConstructionWithOneDimensionalReferenceType() {
|
||||
parseCheck("new String[3]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void arrayConstructionWithOneDimensionalFullyQualifiedReferenceType() {
|
||||
parseCheck("new java.lang.String[3]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void arrayConstructionWithOneDimensionalPrimitiveType() {
|
||||
parseCheck("new int[3]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void arrayConstructionWithMultiDimensionalReferenceType() {
|
||||
parseCheck("new Float[3][4]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void arrayConstructionWithMultiDimensionalPrimitiveType() {
|
||||
parseCheck("new int[3][4]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void arrayConstructionWithOneDimensionalReferenceTypeWithInitializer() {
|
||||
parseCheck("new String[] {'abc','xyz'}");
|
||||
parseCheck("new String[] {'abc', 'xyz'}", "new String[] {'abc','xyz'}");
|
||||
}
|
||||
|
||||
@Test
|
||||
void arrayConstructionWithOneDimensionalPrimitiveTypeWithInitializer() {
|
||||
parseCheck("new int[] {1,2,3,4,5}");
|
||||
parseCheck("new int[] {1, 2, 3, 4, 5}", "new int[] {1,2,3,4,5}");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalDate01() {
|
||||
parseCheck("date('1974/08/24')");
|
||||
@Nested
|
||||
class VariablesAndFunctions {
|
||||
|
||||
@Test
|
||||
void variables() {
|
||||
parseCheck("#foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
void functions() {
|
||||
parseCheck("#fn(1,2,3)");
|
||||
parseCheck("#fn('hello')");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalDate02() {
|
||||
parseCheck("date('19740824T131030','yyyyMMddTHHmmss')");
|
||||
@Nested
|
||||
class ElvisAndTernaryOperators {
|
||||
|
||||
@Test
|
||||
void elvis() {
|
||||
parseCheck("3?:1", "(3 ?: 1)");
|
||||
parseCheck("(2*3)?:1*10", "((2 * 3) ?: (1 * 10))");
|
||||
parseCheck("((2*3)?:1)*10", "(((2 * 3) ?: 1) * 10)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ternary() {
|
||||
parseCheck("1>2?3:4", "((1 > 2) ? 3 : 4)");
|
||||
parseCheck("(a ? 1 : 0) * 10", "((a ? 1 : 0) * 10)");
|
||||
parseCheck("(a?1:0)*10", "((a ? 1 : 0) * 10)");
|
||||
parseCheck("(4 % 2 == 0 ? 1 : 0) * 10", "((((4 % 2) == 0) ? 1 : 0) * 10)");
|
||||
parseCheck("((4 % 2 == 0) ? 1 : 0) * 10", "((((4 % 2) == 0) ? 1 : 0) * 10)");
|
||||
parseCheck("{1}.#isEven(#this) == 'y'?'it is even':'it is odd'",
|
||||
"(({1}.#isEven(#this) == 'y') ? 'it is even' : 'it is odd')");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalNull01() {
|
||||
parseCheck("null");
|
||||
@Nested
|
||||
class TypeReferences {
|
||||
|
||||
@Test
|
||||
void typeReferences01() {
|
||||
parseCheck("T(java.lang.String)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void typeReferences02() {
|
||||
parseCheck("T(String)");
|
||||
}
|
||||
}
|
||||
|
||||
// boolean operators
|
||||
@Test
|
||||
void booleanOperatorsOr01() {
|
||||
parseCheck("false or false", "(false or false)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void booleanOperatorsOr02() {
|
||||
parseCheck("false or true", "(false or true)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void booleanOperatorsOr03() {
|
||||
parseCheck("true or false", "(true or false)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void booleanOperatorsOr04() {
|
||||
parseCheck("true or false", "(true or false)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void booleanOperatorsMix01() {
|
||||
parseCheck("false or true and false", "(false or (true and false))");
|
||||
}
|
||||
|
||||
// relational operators
|
||||
@Test
|
||||
void relOperatorsGT01() {
|
||||
parseCheck("3>6", "(3 > 6)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void relOperatorsLT01() {
|
||||
parseCheck("3<6", "(3 < 6)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void relOperatorsLE01() {
|
||||
parseCheck("3<=6", "(3 <= 6)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void relOperatorsGE01() {
|
||||
parseCheck("3>=6", "(3 >= 6)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void relOperatorsGE02() {
|
||||
parseCheck("3>=3", "(3 >= 3)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void elvis() {
|
||||
parseCheck("3?:1", "(3 ?: 1)");
|
||||
parseCheck("(2*3)?:1*10", "((2 * 3) ?: (1 * 10))");
|
||||
parseCheck("((2*3)?:1)*10", "(((2 * 3) ?: 1) * 10)");
|
||||
}
|
||||
|
||||
// void relOperatorsIn01() {
|
||||
// parseCheck("3 in {1,2,3,4,5}", "(3 in {1,2,3,4,5})");
|
||||
// }
|
||||
//
|
||||
// void relOperatorsBetween01() {
|
||||
// parseCheck("1 between {1, 5}", "(1 between {1,5})");
|
||||
// }
|
||||
|
||||
// void relOperatorsBetween02() {
|
||||
// parseCheck("'efg' between {'abc', 'xyz'}", "('efg' between {'abc','xyz'})");
|
||||
// }// true
|
||||
|
||||
@Test
|
||||
void relOperatorsIs01() {
|
||||
parseCheck("'xyz' instanceof int", "('xyz' instanceof int)");
|
||||
}// false
|
||||
|
||||
// void relOperatorsIs02() {
|
||||
// parseCheck("{1, 2, 3, 4, 5} instanceof List", "({1,2,3,4,5} instanceof List)");
|
||||
// }// true
|
||||
|
||||
@Test
|
||||
void relOperatorsMatches01() {
|
||||
parseCheck("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'", "('5.0067' matches '^-?\\d+(\\.\\d{2})?$')");
|
||||
}// false
|
||||
|
||||
@Test
|
||||
void relOperatorsMatches02() {
|
||||
parseCheck("'5.00' matches '^-?\\d+(\\.\\d{2})?$'", "('5.00' matches '^-?\\d+(\\.\\d{2})?$')");
|
||||
}// true
|
||||
|
||||
// mathematical operators
|
||||
@Test
|
||||
void mathOperatorsAdd01() {
|
||||
parseCheck("2+4", "(2 + 4)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mathOperatorsAdd02() {
|
||||
parseCheck("'a'+'b'", "('a' + 'b')");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mathOperatorsAdd03() {
|
||||
parseCheck("'hello'+' '+'world'", "(('hello' + ' ') + 'world')");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mathOperatorsSubtract01() {
|
||||
parseCheck("5-4", "(5 - 4)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mathOperatorsMultiply01() {
|
||||
parseCheck("7*4", "(7 * 4)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mathOperatorsDivide01() {
|
||||
parseCheck("8/4", "(8 / 4)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mathOperatorModulus01() {
|
||||
parseCheck("7 % 4", "(7 % 4)");
|
||||
}
|
||||
|
||||
// mixed operators
|
||||
@Test
|
||||
void mixedOperators01() {
|
||||
parseCheck("true and 5>3", "(true and (5 > 3))");
|
||||
}
|
||||
|
||||
// collection processors
|
||||
// void collectionProcessorsCount01() {
|
||||
// parseCheck("new String[] {'abc','def','xyz'}.count()");
|
||||
// }
|
||||
|
||||
// void collectionProcessorsCount02() {
|
||||
// parseCheck("new int[] {1,2,3}.count()");
|
||||
// }
|
||||
//
|
||||
// void collectionProcessorsMax01() {
|
||||
// parseCheck("new int[] {1,2,3}.max()");
|
||||
// }
|
||||
//
|
||||
// void collectionProcessorsMin01() {
|
||||
// parseCheck("new int[] {1,2,3}.min()");
|
||||
// }
|
||||
//
|
||||
// void collectionProcessorsAverage01() {
|
||||
// parseCheck("new int[] {1,2,3}.average()");
|
||||
// }
|
||||
//
|
||||
// void collectionProcessorsSort01() {
|
||||
// parseCheck("new int[] {3,2,1}.sort()");
|
||||
// }
|
||||
//
|
||||
// void collectionProcessorsNonNull01() {
|
||||
// parseCheck("{'a','b',null,'d',null}.nonNull()");
|
||||
// }
|
||||
//
|
||||
// void collectionProcessorsDistinct01() {
|
||||
// parseCheck("{'a','b','a','d','e'}.distinct()");
|
||||
// }
|
||||
|
||||
// references
|
||||
@Test
|
||||
void references01() {
|
||||
parseCheck("@foo");
|
||||
parseCheck("@'foo.bar'");
|
||||
parseCheck("@\"foo.bar.goo\"" , "@'foo.bar.goo'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void references03() {
|
||||
parseCheck("@$$foo");
|
||||
}
|
||||
|
||||
// properties
|
||||
@Test
|
||||
void properties01() {
|
||||
parseCheck("name");
|
||||
}
|
||||
|
||||
@Test
|
||||
void properties02() {
|
||||
parseCheck("placeofbirth.CitY");
|
||||
}
|
||||
|
||||
@Test
|
||||
void properties03() {
|
||||
parseCheck("a.b.c.d.e");
|
||||
}
|
||||
|
||||
// inline list creation
|
||||
@Test
|
||||
void inlineListCreation01() {
|
||||
parseCheck("{1, 2, 3, 4, 5}", "{1,2,3,4,5}");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inlineListCreation02() {
|
||||
parseCheck("{'abc','xyz'}", "{'abc','xyz'}");
|
||||
}
|
||||
|
||||
// inline map creation
|
||||
@Test
|
||||
void inlineMapCreation01() {
|
||||
parseCheck("{'key1':'Value 1','today':DateTime.Today}");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inlineMapCreation02() {
|
||||
parseCheck("{1:'January',2:'February',3:'March'}");
|
||||
}
|
||||
|
||||
// methods
|
||||
@Test
|
||||
void methods01() {
|
||||
parseCheck("echo(12)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methods02() {
|
||||
parseCheck("echo(name)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methods03() {
|
||||
parseCheck("age.doubleItAndAdd(12)");
|
||||
}
|
||||
|
||||
// constructors
|
||||
@Test
|
||||
void constructors01() {
|
||||
parseCheck("new String('hello')");
|
||||
}
|
||||
|
||||
// void constructors02() {
|
||||
// parseCheck("new String[3]");
|
||||
// }
|
||||
|
||||
// array construction
|
||||
// void arrayConstruction01() {
|
||||
// parseCheck("new int[] {1, 2, 3, 4, 5}", "new int[] {1,2,3,4,5}");
|
||||
// }
|
||||
//
|
||||
// void arrayConstruction02() {
|
||||
// parseCheck("new String[] {'abc','xyz'}", "new String[] {'abc','xyz'}");
|
||||
// }
|
||||
|
||||
// variables and functions
|
||||
@Test
|
||||
void variables01() {
|
||||
parseCheck("#foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
void functions01() {
|
||||
parseCheck("#fn(1,2,3)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void functions02() {
|
||||
parseCheck("#fn('hello')");
|
||||
}
|
||||
|
||||
// projections and selections
|
||||
// void projections01() {
|
||||
// parseCheck("{1,2,3,4,5,6,7,8,9,10}.!{#isEven()}");
|
||||
// }
|
||||
|
||||
// void selections01() {
|
||||
// parseCheck("{1,2,3,4,5,6,7,8,9,10}.?{#isEven(#this) == 'y'}",
|
||||
// "{1,2,3,4,5,6,7,8,9,10}.?{(#isEven(#this) == 'y')}");
|
||||
// }
|
||||
|
||||
// void selectionsFirst01() {
|
||||
// parseCheck("{1,2,3,4,5,6,7,8,9,10}.^{#isEven(#this) == 'y'}",
|
||||
// "{1,2,3,4,5,6,7,8,9,10}.^{(#isEven(#this) == 'y')}");
|
||||
// }
|
||||
|
||||
// void selectionsLast01() {
|
||||
// parseCheck("{1,2,3,4,5,6,7,8,9,10}.${#isEven(#this) == 'y'}",
|
||||
// "{1,2,3,4,5,6,7,8,9,10}.${(#isEven(#this) == 'y')}");
|
||||
// }
|
||||
|
||||
// assignment
|
||||
@Test
|
||||
void assignmentToVariables01() {
|
||||
parseCheck("#var1='value1'");
|
||||
}
|
||||
|
||||
|
||||
// ternary operator
|
||||
|
||||
@Test
|
||||
void ternaryOperator01() {
|
||||
parseCheck("1>2?3:4", "((1 > 2) ? 3 : 4)");
|
||||
parseCheck("(a ? 1 : 0) * 10", "((a ? 1 : 0) * 10)");
|
||||
parseCheck("(a?1:0)*10", "((a ? 1 : 0) * 10)");
|
||||
parseCheck("(4 % 2 == 0 ? 1 : 0) * 10", "((((4 % 2) == 0) ? 1 : 0) * 10)");
|
||||
parseCheck("((4 % 2 == 0) ? 1 : 0) * 10", "((((4 % 2) == 0) ? 1 : 0) * 10)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ternaryOperator02() {
|
||||
parseCheck("{1}.#isEven(#this) == 'y'?'it is even':'it is odd'",
|
||||
"(({1}.#isEven(#this) == 'y') ? 'it is even' : 'it is odd')");
|
||||
}
|
||||
|
||||
//
|
||||
// void lambdaMax() {
|
||||
// parseCheck("(#max = {|x,y| $x > $y ? $x : $y }; #max(5,25))", "(#max={|x,y| ($x > $y) ? $x : $y };#max(5,25))");
|
||||
// }
|
||||
//
|
||||
// void lambdaFactorial() {
|
||||
// parseCheck("(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #fact(5))",
|
||||
// "(#fact={|n| ($n <= 1) ? 1 : ($n * #fact(($n - 1))) };#fact(5))");
|
||||
// } // 120
|
||||
|
||||
// Type references
|
||||
@Test
|
||||
void typeReferences01() {
|
||||
parseCheck("T(java.lang.String)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void typeReferences02() {
|
||||
parseCheck("T(String)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inlineList1() {
|
||||
parseCheck("{1,2,3,4}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the supplied expression and then create a string representation of the resultant AST, it should be the same
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -209,7 +209,7 @@ class SpelReproTests extends AbstractExpressionTests {
|
||||
checkTemplateParsingError("abc${ } }", "No expression defined within delimiter '${}' at character 3");
|
||||
checkTemplateParsingError("abc$[ } ]", DOLLARSQUARE_TEMPLATE_PARSER_CONTEXT, "Found closing '}' at position 6 without an opening '{'");
|
||||
|
||||
checkTemplateParsing("abc ${\"def''g}hi\"} jkl", "abc def'g}hi jkl");
|
||||
checkTemplateParsing("abc ${\"def''g}hi\"} jkl", "abc def''g}hi jkl");
|
||||
checkTemplateParsing("abc ${'def''g}hi'} jkl", "abc def'g}hi jkl");
|
||||
checkTemplateParsing("}", "}");
|
||||
checkTemplateParsing("${'hello'} world", "hello world");
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.expression.spel;
|
||||
|
||||
import org.junit.platform.suite.api.IncludeClassNamePatterns;
|
||||
import org.junit.platform.suite.api.SelectPackages;
|
||||
import org.junit.platform.suite.api.Suite;
|
||||
|
||||
/**
|
||||
* JUnit Platform based test suite for tests in the spring-expression module.
|
||||
*
|
||||
* <p><strong>This suite is only intended to be used manually within an IDE.</strong>
|
||||
*
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@Suite
|
||||
@SelectPackages("org.springframework.expression.spel")
|
||||
@IncludeClassNamePatterns(".*Tests?$")
|
||||
class SpringExpressionTestSuite {
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -30,15 +30,15 @@ import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Object to represent an SQL BLOB/CLOB value parameter. BLOBs can either be an
|
||||
* InputStream or a byte array. CLOBs can be in the form of a Reader, InputStream
|
||||
* InputStream or a byte array. CLOBs can be in the form of a Reader, InputStream,
|
||||
* or String. Each CLOB/BLOB value will be stored together with its length.
|
||||
* The type is based on which constructor is used. Objects of this class are
|
||||
* immutable except for the LobCreator reference. Use them and discard them.
|
||||
* The type is based on which constructor is used. Instances of this class are
|
||||
* stateful and immutable: use them and discard them.
|
||||
*
|
||||
* <p>This class holds a reference to a LocCreator that must be closed after the
|
||||
* update has completed. This is done via a call to the closeLobCreator method.
|
||||
* All handling of the LobCreator is done by the framework classes that use it -
|
||||
* no need to set or close the LobCreator for end users of this class.
|
||||
* <p>This class holds a reference to a {@link LobCreator} that must be closed after
|
||||
* the update has completed. This is done via a call to the {@link #cleanup()} method.
|
||||
* All handling of the {@code LobCreator} is done by the framework classes that use it -
|
||||
* no need to set or close the {@code LobCreator} for end users of this class.
|
||||
*
|
||||
* <p>A usage example:
|
||||
*
|
||||
@@ -72,8 +72,7 @@ public class SqlLobValue implements DisposableSqlTypeValue {
|
||||
private final int length;
|
||||
|
||||
/**
|
||||
* This contains a reference to the LobCreator - so we can close it
|
||||
* once the update is done.
|
||||
* Reference to the LobCreator - so we can close it once the update is done.
|
||||
*/
|
||||
private final LobCreator lobCreator;
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 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.
|
||||
|
||||
+7
-7
@@ -69,10 +69,10 @@ public class SQLExceptionSubclassTranslator extends AbstractFallbackSQLException
|
||||
if (ex instanceof SQLTransientConnectionException) {
|
||||
return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
else if (ex instanceof SQLTransactionRollbackException) {
|
||||
if (ex instanceof SQLTransactionRollbackException) {
|
||||
return new ConcurrencyFailureException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
else if (ex instanceof SQLTimeoutException) {
|
||||
if (ex instanceof SQLTimeoutException) {
|
||||
return new QueryTimeoutException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
}
|
||||
@@ -80,19 +80,19 @@ public class SQLExceptionSubclassTranslator extends AbstractFallbackSQLException
|
||||
if (ex instanceof SQLNonTransientConnectionException) {
|
||||
return new DataAccessResourceFailureException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
else if (ex instanceof SQLDataException) {
|
||||
if (ex instanceof SQLDataException) {
|
||||
return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
else if (ex instanceof SQLIntegrityConstraintViolationException) {
|
||||
if (ex instanceof SQLIntegrityConstraintViolationException) {
|
||||
return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
else if (ex instanceof SQLInvalidAuthorizationSpecException) {
|
||||
if (ex instanceof SQLInvalidAuthorizationSpecException) {
|
||||
return new PermissionDeniedDataAccessException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
else if (ex instanceof SQLSyntaxErrorException) {
|
||||
if (ex instanceof SQLSyntaxErrorException) {
|
||||
return new BadSqlGrammarException(task, (sql != null ? sql : ""), ex);
|
||||
}
|
||||
else if (ex instanceof SQLFeatureNotSupportedException) {
|
||||
if (ex instanceof SQLFeatureNotSupportedException) {
|
||||
return new InvalidDataAccessApiUsageException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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,6 +16,7 @@
|
||||
|
||||
package org.springframework.jdbc.support;
|
||||
|
||||
import java.sql.SQLDataException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -37,8 +38,8 @@ public class SQLExceptionCustomTranslatorTests {
|
||||
private static SQLErrorCodes ERROR_CODES = new SQLErrorCodes();
|
||||
|
||||
static {
|
||||
ERROR_CODES.setBadSqlGrammarCodes(new String[] { "1" });
|
||||
ERROR_CODES.setDataAccessResourceFailureCodes(new String[] { "2" });
|
||||
ERROR_CODES.setBadSqlGrammarCodes("1");
|
||||
ERROR_CODES.setDataAccessResourceFailureCodes("2");
|
||||
ERROR_CODES.setCustomSqlExceptionTranslatorClass(CustomSqlExceptionTranslator.class);
|
||||
}
|
||||
|
||||
@@ -47,7 +48,7 @@ public class SQLExceptionCustomTranslatorTests {
|
||||
|
||||
@Test
|
||||
public void badSqlGrammarException() {
|
||||
SQLException badSqlGrammarExceptionEx = SQLExceptionSubclassFactory.newSQLDataException("", "", 1);
|
||||
SQLException badSqlGrammarExceptionEx = new SQLDataException("", "", 1);
|
||||
DataAccessException dae = sext.translate("task", "SQL", badSqlGrammarExceptionEx);
|
||||
assertThat(dae.getCause()).isEqualTo(badSqlGrammarExceptionEx);
|
||||
assertThat(dae).isInstanceOf(BadSqlGrammarException.class);
|
||||
@@ -55,7 +56,7 @@ public class SQLExceptionCustomTranslatorTests {
|
||||
|
||||
@Test
|
||||
public void dataAccessResourceException() {
|
||||
SQLException dataAccessResourceEx = SQLExceptionSubclassFactory.newSQLDataException("", "", 2);
|
||||
SQLException dataAccessResourceEx = new SQLDataException("", "", 2);
|
||||
DataAccessException dae = sext.translate("task", "SQL", dataAccessResourceEx);
|
||||
assertThat(dae.getCause()).isEqualTo(dataAccessResourceEx);
|
||||
assertThat(dae).isInstanceOf(TransientDataAccessResourceException.class);
|
||||
|
||||
-78
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.support;
|
||||
|
||||
import java.sql.SQLDataException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.SQLIntegrityConstraintViolationException;
|
||||
import java.sql.SQLInvalidAuthorizationSpecException;
|
||||
import java.sql.SQLNonTransientConnectionException;
|
||||
import java.sql.SQLRecoverableException;
|
||||
import java.sql.SQLSyntaxErrorException;
|
||||
import java.sql.SQLTimeoutException;
|
||||
import java.sql.SQLTransactionRollbackException;
|
||||
import java.sql.SQLTransientConnectionException;
|
||||
|
||||
/**
|
||||
* Class to generate {@link SQLException} subclasses for testing purposes.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
*/
|
||||
public class SQLExceptionSubclassFactory {
|
||||
|
||||
public static SQLException newSQLDataException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLDataException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLFeatureNotSupportedException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLFeatureNotSupportedException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLIntegrityConstraintViolationException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLIntegrityConstraintViolationException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLInvalidAuthorizationSpecException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLInvalidAuthorizationSpecException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLNonTransientConnectionException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLNonTransientConnectionException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLSyntaxErrorException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLSyntaxErrorException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLTransactionRollbackException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLTransactionRollbackException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLTransientConnectionException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLTransientConnectionException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLTimeoutException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLTimeoutException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLRecoverableException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLRecoverableException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
}
|
||||
+39
-65
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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,11 +16,22 @@
|
||||
|
||||
package org.springframework.jdbc.support;
|
||||
|
||||
import java.sql.SQLDataException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.SQLIntegrityConstraintViolationException;
|
||||
import java.sql.SQLInvalidAuthorizationSpecException;
|
||||
import java.sql.SQLNonTransientConnectionException;
|
||||
import java.sql.SQLRecoverableException;
|
||||
import java.sql.SQLSyntaxErrorException;
|
||||
import java.sql.SQLTimeoutException;
|
||||
import java.sql.SQLTransactionRollbackException;
|
||||
import java.sql.SQLTransientConnectionException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
@@ -34,78 +45,41 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class SQLExceptionSubclassTranslatorTests {
|
||||
|
||||
private static SQLErrorCodes ERROR_CODES = new SQLErrorCodes();
|
||||
@Test
|
||||
public void exceptionClassTranslation() {
|
||||
doTest(new SQLDataException("", "", 0), DataIntegrityViolationException.class);
|
||||
doTest(new SQLFeatureNotSupportedException("", "", 0), InvalidDataAccessApiUsageException.class);
|
||||
doTest(new SQLIntegrityConstraintViolationException("", "", 0), DataIntegrityViolationException.class);
|
||||
doTest(new SQLInvalidAuthorizationSpecException("", "", 0), PermissionDeniedDataAccessException.class);
|
||||
doTest(new SQLNonTransientConnectionException("", "", 0), DataAccessResourceFailureException.class);
|
||||
doTest(new SQLRecoverableException("", "", 0), RecoverableDataAccessException.class);
|
||||
doTest(new SQLSyntaxErrorException("", "", 0), BadSqlGrammarException.class);
|
||||
doTest(new SQLTimeoutException("", "", 0), QueryTimeoutException.class);
|
||||
doTest(new SQLTransactionRollbackException("", "", 0), ConcurrencyFailureException.class);
|
||||
doTest(new SQLTransientConnectionException("", "", 0), TransientDataAccessResourceException.class);
|
||||
}
|
||||
|
||||
static {
|
||||
ERROR_CODES.setBadSqlGrammarCodes("1");
|
||||
@Test
|
||||
public void fallbackStateTranslation() {
|
||||
// Test fallback. We assume that no database will ever return this error code,
|
||||
// but 07xxx will be bad grammar picked up by the fallback SQLState translator
|
||||
doTest(new SQLException("", "07xxx", 666666666), BadSqlGrammarException.class);
|
||||
// and 08xxx will be data resource failure (non-transient) picked up by the fallback SQLState translator
|
||||
doTest(new SQLException("", "08xxx", 666666666), DataAccessResourceFailureException.class);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void errorCodeTranslation() {
|
||||
SQLExceptionTranslator sext = new SQLErrorCodeSQLExceptionTranslator(ERROR_CODES);
|
||||
private void doTest(SQLException ex, Class<?> dataAccessExceptionType) {
|
||||
SQLExceptionTranslator translator = new SQLExceptionSubclassTranslator();
|
||||
DataAccessException dax = translator.translate("task", "SQL", ex);
|
||||
|
||||
SQLException dataIntegrityViolationEx = SQLExceptionSubclassFactory.newSQLDataException("", "", 0);
|
||||
DataIntegrityViolationException divex = (DataIntegrityViolationException) sext.translate("task", "SQL", dataIntegrityViolationEx);
|
||||
assertThat(divex.getCause()).isEqualTo(dataIntegrityViolationEx);
|
||||
|
||||
SQLException featureNotSupEx = SQLExceptionSubclassFactory.newSQLFeatureNotSupportedException("", "", 0);
|
||||
InvalidDataAccessApiUsageException idaex = (InvalidDataAccessApiUsageException) sext.translate("task", "SQL", featureNotSupEx);
|
||||
assertThat(idaex.getCause()).isEqualTo(featureNotSupEx);
|
||||
|
||||
SQLException dataIntegrityViolationEx2 = SQLExceptionSubclassFactory.newSQLIntegrityConstraintViolationException("", "", 0);
|
||||
DataIntegrityViolationException divex2 = (DataIntegrityViolationException) sext.translate("task", "SQL", dataIntegrityViolationEx2);
|
||||
assertThat(divex2.getCause()).isEqualTo(dataIntegrityViolationEx2);
|
||||
|
||||
SQLException permissionDeniedEx = SQLExceptionSubclassFactory.newSQLInvalidAuthorizationSpecException("", "", 0);
|
||||
PermissionDeniedDataAccessException pdaex = (PermissionDeniedDataAccessException) sext.translate("task", "SQL", permissionDeniedEx);
|
||||
assertThat(pdaex.getCause()).isEqualTo(permissionDeniedEx);
|
||||
|
||||
SQLException dataAccessResourceEx = SQLExceptionSubclassFactory.newSQLNonTransientConnectionException("", "", 0);
|
||||
DataAccessResourceFailureException darex = (DataAccessResourceFailureException) sext.translate("task", "SQL", dataAccessResourceEx);
|
||||
assertThat(darex.getCause()).isEqualTo(dataAccessResourceEx);
|
||||
|
||||
SQLException badSqlEx2 = SQLExceptionSubclassFactory.newSQLSyntaxErrorException("", "", 0);
|
||||
BadSqlGrammarException bsgex2 = (BadSqlGrammarException) sext.translate("task", "SQL2", badSqlEx2);
|
||||
assertThat(bsgex2.getSql()).isEqualTo("SQL2");
|
||||
assertThat((Object) bsgex2.getSQLException()).isEqualTo(badSqlEx2);
|
||||
|
||||
SQLException tranRollbackEx = SQLExceptionSubclassFactory.newSQLTransactionRollbackException("", "", 0);
|
||||
ConcurrencyFailureException cfex = (ConcurrencyFailureException) sext.translate("task", "SQL", tranRollbackEx);
|
||||
assertThat(cfex.getCause()).isEqualTo(tranRollbackEx);
|
||||
|
||||
SQLException transientConnEx = SQLExceptionSubclassFactory.newSQLTransientConnectionException("", "", 0);
|
||||
TransientDataAccessResourceException tdarex = (TransientDataAccessResourceException) sext.translate("task", "SQL", transientConnEx);
|
||||
assertThat(tdarex.getCause()).isEqualTo(transientConnEx);
|
||||
|
||||
SQLException transientConnEx2 = SQLExceptionSubclassFactory.newSQLTimeoutException("", "", 0);
|
||||
QueryTimeoutException tdarex2 = (QueryTimeoutException) sext.translate("task", "SQL", transientConnEx2);
|
||||
assertThat(tdarex2.getCause()).isEqualTo(transientConnEx2);
|
||||
|
||||
SQLException recoverableEx = SQLExceptionSubclassFactory.newSQLRecoverableException("", "", 0);
|
||||
RecoverableDataAccessException rdaex2 = (RecoverableDataAccessException) sext.translate("task", "SQL", recoverableEx);
|
||||
assertThat(rdaex2.getCause()).isEqualTo(recoverableEx);
|
||||
|
||||
// Test classic error code translation. We should move there next if the exception we pass in is not one
|
||||
// of the new subclasses.
|
||||
SQLException sexEct = new SQLException("", "", 1);
|
||||
BadSqlGrammarException bsgEct = (BadSqlGrammarException) sext.translate("task", "SQL-ECT", sexEct);
|
||||
assertThat(bsgEct.getSql()).isEqualTo("SQL-ECT");
|
||||
assertThat((Object) bsgEct.getSQLException()).isEqualTo(sexEct);
|
||||
|
||||
// Test fallback. We assume that no database will ever return this error code,
|
||||
// but 07xxx will be bad grammar picked up by the fallback SQLState translator
|
||||
SQLException sexFbt = new SQLException("", "07xxx", 666666666);
|
||||
BadSqlGrammarException bsgFbt = (BadSqlGrammarException) sext.translate("task", "SQL-FBT", sexFbt);
|
||||
assertThat(bsgFbt.getSql()).isEqualTo("SQL-FBT");
|
||||
assertThat((Object) bsgFbt.getSQLException()).isEqualTo(sexFbt);
|
||||
// and 08xxx will be data resource failure (non-transient) picked up by the fallback SQLState translator
|
||||
SQLException sexFbt2 = new SQLException("", "08xxx", 666666666);
|
||||
DataAccessResourceFailureException darfFbt = (DataAccessResourceFailureException) sext.translate("task", "SQL-FBT2", sexFbt2);
|
||||
assertThat(darfFbt.getCause()).isEqualTo(sexFbt2);
|
||||
assertThat(dax).as("Specific translation must not result in null").isNotNull();
|
||||
assertThat(dax).as("Wrong DataAccessException type returned").isExactlyInstanceOf(dataAccessExceptionType);
|
||||
assertThat(dax.getCause()).as("The exact same original SQLException must be preserved").isSameAs(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.support;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.jdbc.BadSqlGrammarException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
* @since 13-Jan-03
|
||||
*/
|
||||
public class SQLStateExceptionTranslatorTests {
|
||||
|
||||
private static final String sql = "SELECT FOO FROM BAR";
|
||||
|
||||
private final SQLStateSQLExceptionTranslator trans = new SQLStateSQLExceptionTranslator();
|
||||
|
||||
// ALSO CHECK CHAIN of SQLExceptions!?
|
||||
// also allow chain of translators? default if can't do specific?
|
||||
|
||||
@Test
|
||||
public void badSqlGrammar() {
|
||||
SQLException sex = new SQLException("Message", "42001", 1);
|
||||
try {
|
||||
throw this.trans.translate("task", sql, sex);
|
||||
}
|
||||
catch (BadSqlGrammarException ex) {
|
||||
// OK
|
||||
assertThat(sql.equals(ex.getSql())).as("SQL is correct").isTrue();
|
||||
assertThat(sex.equals(ex.getSQLException())).as("Exception matches").isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidSqlStateCode() {
|
||||
SQLException sex = new SQLException("Message", "NO SUCH CODE", 1);
|
||||
assertThat(this.trans.translate("task", sql, sex)).isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* PostgreSQL can return null.
|
||||
* SAP DB can apparently return empty SQL code.
|
||||
* Bug 729170
|
||||
*/
|
||||
@Test
|
||||
public void malformedSqlStateCodes() {
|
||||
SQLException sex = new SQLException("Message", null, 1);
|
||||
assertThat(this.trans.translate("task", sql, sex)).isNull();
|
||||
|
||||
sex = new SQLException("Message", "", 1);
|
||||
assertThat(this.trans.translate("task", sql, sex)).isNull();
|
||||
|
||||
// One char's not allowed
|
||||
sex = new SQLException("Message", "I", 1);
|
||||
assertThat(this.trans.translate("task", sql, sex)).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
+39
-23
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,6 +26,7 @@ import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.TransientDataAccessResourceException;
|
||||
import org.springframework.jdbc.BadSqlGrammarException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
@@ -37,58 +38,73 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
*/
|
||||
public class SQLStateSQLExceptionTranslatorTests {
|
||||
|
||||
private static final String REASON = "The game is afoot!";
|
||||
|
||||
private static final String TASK = "Counting sheep... yawn.";
|
||||
|
||||
private static final String SQL = "select count(0) from t_sheep where over_fence = ... yawn... 1";
|
||||
|
||||
|
||||
@Test
|
||||
public void testTranslateNullException() {
|
||||
public void translateNullException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
||||
new SQLStateSQLExceptionTranslator().translate("", "", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranslateBadSqlGrammar() {
|
||||
public void translateBadSqlGrammar() {
|
||||
doTest("07", BadSqlGrammarException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranslateDataIntegrityViolation() {
|
||||
public void translateDataIntegrityViolation() {
|
||||
doTest("23", DataIntegrityViolationException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranslateDataAccessResourceFailure() {
|
||||
public void translateDataAccessResourceFailure() {
|
||||
doTest("53", DataAccessResourceFailureException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranslateTransientDataAccessResourceFailure() {
|
||||
public void translateTransientDataAccessResourceFailure() {
|
||||
doTest("S1", TransientDataAccessResourceException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranslateConcurrencyFailure() {
|
||||
public void translateConcurrencyFailure() {
|
||||
doTest("40", ConcurrencyFailureException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranslateUncategorized() {
|
||||
assertThat(new SQLStateSQLExceptionTranslator().translate("", "", new SQLException(REASON, "00000000"))).isNull();
|
||||
public void translateUncategorized() {
|
||||
doTest("00000000", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidSqlStateCode() {
|
||||
doTest("NO SUCH CODE", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* PostgreSQL can return null.
|
||||
* SAP DB can apparently return empty SQL code.
|
||||
* Bug 729170
|
||||
*/
|
||||
@Test
|
||||
public void malformedSqlStateCodes() {
|
||||
doTest(null, null);
|
||||
doTest("", null);
|
||||
doTest("I", null);
|
||||
}
|
||||
|
||||
|
||||
private void doTest(String sqlState, Class<?> dataAccessExceptionType) {
|
||||
SQLException ex = new SQLException(REASON, sqlState);
|
||||
private void doTest(@Nullable String sqlState, @Nullable Class<?> dataAccessExceptionType) {
|
||||
SQLExceptionTranslator translator = new SQLStateSQLExceptionTranslator();
|
||||
DataAccessException dax = translator.translate(TASK, SQL, ex);
|
||||
assertThat(dax).as("Specific translation must not result in a null DataAccessException being returned.").isNotNull();
|
||||
assertThat(dax.getClass()).as("Wrong DataAccessException type returned as the result of the translation").isEqualTo(dataAccessExceptionType);
|
||||
assertThat(dax.getCause()).as("The original SQLException must be preserved in the translated DataAccessException").isNotNull();
|
||||
assertThat(dax.getCause()).as("The exact same original SQLException must be preserved in the translated DataAccessException").isSameAs(ex);
|
||||
SQLException ex = new SQLException("reason", sqlState);
|
||||
DataAccessException dax = translator.translate("task", "SQL", ex);
|
||||
|
||||
if (dataAccessExceptionType == null) {
|
||||
assertThat(dax).as("Expected translation to null").isNull();
|
||||
return;
|
||||
}
|
||||
|
||||
assertThat(dax).as("Specific translation must not result in null").isNotNull();
|
||||
assertThat(dax).as("Wrong DataAccessException type returned").isExactlyInstanceOf(dataAccessExceptionType);
|
||||
assertThat(dax.getCause()).as("The exact same original SQLException must be preserved").isSameAs(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -193,7 +193,13 @@ public abstract class JmsAccessor implements InitializingBean {
|
||||
* @see javax.jms.ConnectionFactory#createConnection()
|
||||
*/
|
||||
protected Connection createConnection() throws JMSException {
|
||||
return obtainConnectionFactory().createConnection();
|
||||
ConnectionFactory cf = obtainConnectionFactory();
|
||||
Connection con = cf.createConnection();
|
||||
if (con == null) {
|
||||
throw new javax.jms.IllegalStateException(
|
||||
"ConnectionFactory returned null from createConnection(): " + cf);
|
||||
}
|
||||
return con;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,7 +26,7 @@ import java.util.Locale;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.annotation.SynthesizingMethodParameter;
|
||||
import org.springframework.messaging.Message;
|
||||
@@ -81,7 +81,7 @@ public class PayloadMethodArgumentResolverTests {
|
||||
this.paramAnnotatedRequired = new SynthesizingMethodParameter(payloadMethod, 2);
|
||||
this.paramWithSpelExpression = new SynthesizingMethodParameter(payloadMethod, 3);
|
||||
this.paramValidated = new SynthesizingMethodParameter(payloadMethod, 4);
|
||||
this.paramValidated.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
this.paramValidated.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
|
||||
this.paramValidatedNotAnnotated = new SynthesizingMethodParameter(payloadMethod, 5);
|
||||
this.paramNotAnnotated = new SynthesizingMethodParameter(payloadMethod, 6);
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,7 +39,7 @@ import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.Enhancer;
|
||||
import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodIntrospector;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
@@ -131,7 +131,7 @@ public class ResolvableMethod {
|
||||
|
||||
private static final SpringObjenesis objenesis = new SpringObjenesis();
|
||||
|
||||
private static final ParameterNameDiscoverer nameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
private static final ParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
|
||||
|
||||
// Matches ValueConstants.DEFAULT_NONE (spring-web and spring-messaging)
|
||||
private static final String DEFAULT_VALUE_NONE = "\n\t\t\n\t\t\n\uE000\uE001\uE002\n\t\t\t\t\n";
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 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.
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.
|
||||
@@ -221,7 +221,7 @@ public abstract class ConnectionFactoryUtils {
|
||||
return new QueryTimeoutException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
}
|
||||
if (ex instanceof R2dbcNonTransientException) {
|
||||
else if (ex instanceof R2dbcNonTransientException) {
|
||||
if (ex instanceof R2dbcNonTransientResourceException) {
|
||||
return new DataAccessResourceFailureException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
|
||||
+11
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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,19 +17,15 @@
|
||||
package org.springframework.test.web.servlet.samples.spr;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.filter.CharacterEncodingFilter;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
|
||||
/**
|
||||
@@ -37,26 +33,23 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
|
||||
*
|
||||
* @author Wesley Hall
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@WebAppConfiguration
|
||||
@ContextConfiguration
|
||||
public class MockMvcBuilderMethodChainTests {
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext wac;
|
||||
@SpringJUnitWebConfig
|
||||
class MockMvcBuilderMethodChainTests {
|
||||
|
||||
@Test
|
||||
public void chainMultiple() {
|
||||
MockMvcBuilders
|
||||
void chainMultiple(WebApplicationContext wac) {
|
||||
assertThatNoException().isThrownBy(() ->
|
||||
MockMvcBuilders
|
||||
.webAppContextSetup(wac)
|
||||
.addFilter(new CharacterEncodingFilter() )
|
||||
.defaultRequest(get("/").contextPath("/mywebapp"))
|
||||
.build();
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class WebConfig implements WebMvcConfigurer {
|
||||
static class WebConfig {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -20,6 +20,9 @@ package org.springframework.dao;
|
||||
* Exception thrown on failure to acquire a lock during an update,
|
||||
* for example during a "select for update" statement.
|
||||
*
|
||||
* <p>Consider handling the general {@link PessimisticLockingFailureException}
|
||||
* instead, semantically including a wider range of locking-related failures.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
||||
+4
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -20,6 +20,9 @@ package org.springframework.dao;
|
||||
* Exception thrown on failure to complete a transaction in serialized mode
|
||||
* due to update conflicts.
|
||||
*
|
||||
* <p>Consider handling the general {@link PessimisticLockingFailureException}
|
||||
* instead, semantically including a wider range of locking-related failures.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -19,17 +19,15 @@ package org.springframework.dao;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Exception thrown on concurrency failure.
|
||||
* Exception thrown on various data access concurrency failures.
|
||||
*
|
||||
* <p>This exception should be subclassed to indicate the type of failure:
|
||||
* optimistic locking, failure to acquire lock, etc.
|
||||
* <p>This exception provides subclasses for specific types of failure,
|
||||
* in particular optimistic locking versus pessimistic locking.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 1.1
|
||||
* @see OptimisticLockingFailureException
|
||||
* @see PessimisticLockingFailureException
|
||||
* @see CannotAcquireLockException
|
||||
* @see DeadlockLoserDataAccessException
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ConcurrencyFailureException extends TransientDataAccessException {
|
||||
|
||||
+7
-2
@@ -19,8 +19,13 @@ package org.springframework.dao;
|
||||
/**
|
||||
* Exception thrown when an attempt to insert or update data
|
||||
* results in violation of an integrity constraint. Note that this
|
||||
* is not purely a relational concept; unique primary keys are
|
||||
* required by most database types.
|
||||
* is not purely a relational concept; integrity constraints such
|
||||
* as unique primary keys are required by most database types.
|
||||
*
|
||||
* <p>Serves as a superclass for more specific exceptions, e.g.
|
||||
* {@link DuplicateKeyException}. However, it is generally
|
||||
* recommended to handle {@code DataIntegrityViolationException}
|
||||
* itself instead of relying on specific exception subclasses.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
|
||||
+4
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -20,6 +20,9 @@ package org.springframework.dao;
|
||||
* Generic exception thrown when the current process was
|
||||
* a deadlock loser, and its transaction rolled back.
|
||||
*
|
||||
* <p>Consider handling the general {@link PessimisticLockingFailureException}
|
||||
* instead, semantically including a wider range of locking-related failures.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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,6 +22,9 @@ package org.springframework.dao;
|
||||
* Note that this is not necessarily a purely relational concept;
|
||||
* unique primary keys are required by most database types.
|
||||
*
|
||||
* <p>Consider handling the general {@link DataIntegrityViolationException}
|
||||
* instead, semantically including a wider range of constraint violations.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -21,13 +21,13 @@ package org.springframework.dao;
|
||||
* Thrown by Spring's SQLException translation mechanism
|
||||
* if a corresponding database error is encountered.
|
||||
*
|
||||
* <p>Serves as superclass for more specific exceptions, like
|
||||
* CannotAcquireLockException and DeadlockLoserDataAccessException.
|
||||
* <p>Serves as a superclass for more specific exceptions, e.g.
|
||||
* {@link CannotAcquireLockException}. However, it is generally
|
||||
* recommended to handle {@code PessimisticLockingFailureException}
|
||||
* itself instead of relying on specific exception subclasses.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 1.2
|
||||
* @see CannotAcquireLockException
|
||||
* @see DeadlockLoserDataAccessException
|
||||
* @see OptimisticLockingFailureException
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
|
||||
@@ -233,9 +233,9 @@ public final class ContentDisposition {
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.filename);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.charset);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.size);
|
||||
result = 31 * result + (this.creationDate != null ? this.creationDate.hashCode() : 0);
|
||||
result = 31 * result + (this.modificationDate != null ? this.modificationDate.hashCode() : 0);
|
||||
result = 31 * result + (this.readDate != null ? this.readDate.hashCode() : 0);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.creationDate);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.modificationDate);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.readDate);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ public final class ContentDisposition {
|
||||
if (idx1 != -1 && idx2 != -1) {
|
||||
charset = Charset.forName(value.substring(0, idx1).trim());
|
||||
Assert.isTrue(UTF_8.equals(charset) || ISO_8859_1.equals(charset),
|
||||
"Charset should be UTF-8 or ISO-8859-1");
|
||||
"Charset must be UTF-8 or ISO-8859-1");
|
||||
filename = decodeFilename(value.substring(idx2 + 1), charset);
|
||||
}
|
||||
else {
|
||||
@@ -532,10 +532,11 @@ public final class ContentDisposition {
|
||||
* @see <a href="https://tools.ietf.org/html/rfc5987">RFC 5987</a>
|
||||
*/
|
||||
private static String encodeFilename(String input, Charset charset) {
|
||||
Assert.notNull(input, "'input' is required");
|
||||
Assert.notNull(charset, "'charset' is required");
|
||||
Assert.notNull(input, "'input' must not be null");
|
||||
Assert.notNull(charset, "'charset' must not be null");
|
||||
Assert.isTrue(!StandardCharsets.US_ASCII.equals(charset), "ASCII does not require encoding");
|
||||
Assert.isTrue(UTF_8.equals(charset) || ISO_8859_1.equals(charset), "Only UTF-8 and ISO-8859-1 are supported");
|
||||
|
||||
byte[] source = input.getBytes(charset);
|
||||
int len = source.length;
|
||||
StringBuilder sb = new StringBuilder(len << 1);
|
||||
|
||||
@@ -984,7 +984,8 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
/**
|
||||
* Return the {@linkplain MediaType media type} of the body, as specified
|
||||
* by the {@code Content-Type} header.
|
||||
* <p>Returns {@code null} when the content-type is unknown.
|
||||
* <p>Returns {@code null} when the {@code Content-Type} header is not set.
|
||||
* @throws InvalidMediaTypeException if the media type value cannot be parsed
|
||||
*/
|
||||
@Nullable
|
||||
public MediaType getContentType() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -170,7 +170,6 @@ class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
||||
public Iterator<Entry<String, List<String>>> iterator() {
|
||||
return new EntryIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return headers.size();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -92,11 +92,11 @@ public interface ClientCodecConfigurer extends CodecConfigurer {
|
||||
|
||||
/**
|
||||
* Configure the {@code Decoder} to use for Server-Sent Events.
|
||||
* <p>By default if this is not set, and Jackson is available, the
|
||||
* {@link #jackson2JsonDecoder} override is used instead. Use this property
|
||||
* if you want to further customize the SSE decoder.
|
||||
* <p>Note that {@link #maxInMemorySize(int)}, if configured, will be
|
||||
* applied to the given decoder.
|
||||
* <p>By default if this is not set, and Jackson is available,
|
||||
* the {@link #jackson2JsonDecoder} override is used instead.
|
||||
* Use this method to customize the SSE decoder.
|
||||
* <p>Note that {@link #maxInMemorySize(int)}, if configured,
|
||||
* will be applied to the given decoder.
|
||||
* @param decoder the decoder to use
|
||||
*/
|
||||
void serverSentEventDecoder(Decoder<?> decoder);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -78,7 +78,7 @@ public interface ServerCodecConfigurer extends CodecConfigurer {
|
||||
|
||||
|
||||
/**
|
||||
* {@link CodecConfigurer.DefaultCodecs} extension with extra client-side options.
|
||||
* {@link CodecConfigurer.DefaultCodecs} extension with extra server-side options.
|
||||
*/
|
||||
interface ServerDefaultCodecs extends DefaultCodecs {
|
||||
|
||||
@@ -101,9 +101,9 @@ public interface ServerCodecConfigurer extends CodecConfigurer {
|
||||
|
||||
/**
|
||||
* Configure the {@code Encoder} to use for Server-Sent Events.
|
||||
* <p>By default if this is not set, and Jackson is available, the
|
||||
* {@link #jackson2JsonEncoder} override is used instead. Use this method
|
||||
* to customize the SSE encoder.
|
||||
* <p>By default if this is not set, and Jackson is available,
|
||||
* the {@link #jackson2JsonEncoder} override is used instead.
|
||||
* Use this method to customize the SSE encoder.
|
||||
*/
|
||||
void serverSentEventEncoder(Encoder<?> encoder);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -170,7 +170,6 @@ class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
||||
public Iterator<Entry<String, List<String>>> iterator() {
|
||||
return new EntryIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return headers.size();
|
||||
|
||||
+7
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -65,12 +65,12 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||
protected ServletServerHttpRequest createRequest(HttpServletRequest request, AsyncContext context)
|
||||
throws IOException, URISyntaxException {
|
||||
|
||||
// TODO: need to compile against Jetty 10 to use HttpFields (class->interface)
|
||||
if (jetty10Present) {
|
||||
// No HttpFields optimization on Jetty 10 due to binary incompatibility
|
||||
return super.createRequest(request, context);
|
||||
}
|
||||
|
||||
Assert.notNull(getServletPath(), "Servlet path is not initialized");
|
||||
Assert.state(getServletPath() != null, "Servlet path is not initialized");
|
||||
return new JettyServerHttpRequest(
|
||||
request, context, getServletPath(), getDataBufferFactory(), getBufferSize());
|
||||
}
|
||||
@@ -79,15 +79,14 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||
protected ServletServerHttpResponse createResponse(HttpServletResponse response,
|
||||
AsyncContext context, ServletServerHttpRequest request) throws IOException {
|
||||
|
||||
// TODO: need to compile against Jetty 10 to use HttpFields (class->interface)
|
||||
if (jetty10Present) {
|
||||
// No HttpFields optimization on Jetty 10 due to binary incompatibility
|
||||
return new BaseJettyServerHttpResponse(
|
||||
response, context, getDataBufferFactory(), getBufferSize(), request);
|
||||
}
|
||||
else {
|
||||
return new JettyServerHttpResponse(
|
||||
response, context, getDataBufferFactory(), getBufferSize(), request);
|
||||
}
|
||||
|
||||
return new JettyServerHttpResponse(
|
||||
response, context, getDataBufferFactory(), getBufferSize(), request);
|
||||
}
|
||||
|
||||
|
||||
@@ -120,8 +119,6 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||
"] to org.eclipse.jetty.server.Request");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+9
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -170,7 +170,7 @@ public class ServletHttpHandlerAdapter implements Servlet {
|
||||
AsyncListener requestListener;
|
||||
String logPrefix;
|
||||
try {
|
||||
httpRequest = createRequest(((HttpServletRequest) request), asyncContext);
|
||||
httpRequest = createRequest((HttpServletRequest) request, asyncContext);
|
||||
requestListener = httpRequest.getAsyncListener();
|
||||
logPrefix = httpRequest.getLogPrefix();
|
||||
}
|
||||
@@ -183,8 +183,10 @@ public class ServletHttpHandlerAdapter implements Servlet {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerHttpResponse httpResponse = createResponse(((HttpServletResponse) response), asyncContext, httpRequest);
|
||||
AsyncListener responseListener = ((ServletServerHttpResponse) httpResponse).getAsyncListener();
|
||||
ServletServerHttpResponse wrappedResponse =
|
||||
createResponse((HttpServletResponse) response, asyncContext, httpRequest);
|
||||
ServerHttpResponse httpResponse = wrappedResponse;
|
||||
AsyncListener responseListener = wrappedResponse.getAsyncListener();
|
||||
if (httpRequest.getMethod() == HttpMethod.HEAD) {
|
||||
httpResponse = new HttpHeadResponseDecorator(httpResponse);
|
||||
}
|
||||
@@ -201,7 +203,7 @@ public class ServletHttpHandlerAdapter implements Servlet {
|
||||
protected ServletServerHttpRequest createRequest(HttpServletRequest request, AsyncContext context)
|
||||
throws IOException, URISyntaxException {
|
||||
|
||||
Assert.notNull(this.servletPath, "Servlet path is not initialized");
|
||||
Assert.state(this.servletPath != null, "Servlet path is not initialized");
|
||||
return new ServletServerHttpRequest(
|
||||
request, context, this.servletPath, getDataBufferFactory(), getBufferSize());
|
||||
}
|
||||
@@ -264,9 +266,7 @@ public class ServletHttpHandlerAdapter implements Servlet {
|
||||
|
||||
private final String logPrefix;
|
||||
|
||||
|
||||
public HttpHandlerAsyncListener(
|
||||
AsyncListener requestAsyncListener, AsyncListener responseAsyncListener,
|
||||
public HttpHandlerAsyncListener(AsyncListener requestAsyncListener, AsyncListener responseAsyncListener,
|
||||
Runnable handlerDisposeTask, AtomicBoolean completionFlag, String logPrefix) {
|
||||
|
||||
this.requestAsyncListener = requestAsyncListener;
|
||||
@@ -276,7 +276,6 @@ public class ServletHttpHandlerAdapter implements Servlet {
|
||||
this.logPrefix = logPrefix;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onTimeout(AsyncEvent event) {
|
||||
// Should never happen since we call asyncContext.setTimeout(-1)
|
||||
@@ -362,9 +361,7 @@ public class ServletHttpHandlerAdapter implements Servlet {
|
||||
@Nullable
|
||||
private volatile Subscription subscription;
|
||||
|
||||
public HandlerResultSubscriber(
|
||||
AsyncContext asyncContext, AtomicBoolean completionFlag, String logPrefix) {
|
||||
|
||||
public HandlerResultSubscriber(AsyncContext asyncContext, AtomicBoolean completionFlag, String logPrefix) {
|
||||
this.asyncContext = asyncContext;
|
||||
this.completionFlag = completionFlag;
|
||||
this.logPrefix = logPrefix;
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.
|
||||
@@ -58,7 +58,6 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||
|
||||
|
||||
public TomcatHttpHandlerAdapter(HttpHandler httpHandler) {
|
||||
super(httpHandler);
|
||||
}
|
||||
@@ -68,7 +67,7 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||
protected ServletServerHttpRequest createRequest(HttpServletRequest request, AsyncContext asyncContext)
|
||||
throws IOException, URISyntaxException {
|
||||
|
||||
Assert.notNull(getServletPath(), "Servlet path is not initialized");
|
||||
Assert.state(getServletPath() != null, "Servlet path is not initialized");
|
||||
return new TomcatServerHttpRequest(
|
||||
request, asyncContext, getServletPath(), getDataBufferFactory(), getBufferSize());
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 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.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user