mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
126 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 445e8ea84a | |||
| df60919bb0 | |||
| 2f1f36eeda | |||
| 1c0a4f8d78 | |||
| cc376ac5ed | |||
| 10c9d2fcec | |||
| 439ffe2e8a | |||
| 4e55262521 | |||
| ebd2ec57fc | |||
| f536819c5d | |||
| af75c6db2f | |||
| d12619cf1f | |||
| 4c1d227776 | |||
| da02b7a141 | |||
| 17117bd21a | |||
| 0d7494ac52 | |||
| a59a33846e | |||
| 51b8ba334a | |||
| abc2269d97 | |||
| ff385aaf7b | |||
| 1b50ca6bd3 | |||
| 6bae759349 | |||
| e1e8c165db | |||
| 6699833121 | |||
| 095acefd7e | |||
| b62e066b7d | |||
| 9969cb6d83 | |||
| 04b3f5a247 | |||
| c91b47fded | |||
| f2c364b491 | |||
| 170adccf80 | |||
| 98390e1e5e | |||
| 6df8c2678b | |||
| 7f49abb6d1 | |||
| b9bf56e41d | |||
| d0e3e2acfc | |||
| 18d983c686 | |||
| d8abbc501e | |||
| 6ce19ff861 | |||
| c8ef49cc8e | |||
| f61983d908 | |||
| 7615e0b036 | |||
| afe22b84c2 | |||
| 634aba4ab6 | |||
| 26a2d3875f | |||
| 802d083df7 | |||
| f5b43a264a | |||
| 59e4755562 | |||
| 2576aa4063 | |||
| 3fbe762832 | |||
| 611bb0b92e | |||
| 32a8b9b25a | |||
| 97cad6ca8e | |||
| 015f7d8ce1 | |||
| da4e2710b4 | |||
| a368040fd6 | |||
| 5dbd3b0bbf | |||
| 197dbffe20 | |||
| 5341e77796 | |||
| f049a6ec16 | |||
| 7203da7133 | |||
| a21df0cc6d | |||
| 83683a13bb | |||
| 59165dd526 | |||
| 25554d0b21 | |||
| 4f86282b14 | |||
| b3237f3eb6 | |||
| fd68fb115d | |||
| 43e047c523 | |||
| 7fdf775394 | |||
| 59084c6b73 | |||
| 4fcc09a02c | |||
| f5b082d3b3 | |||
| c164759c41 | |||
| 2179b67706 | |||
| fbde98f36e | |||
| 529f8ba786 | |||
| f4676bb41c | |||
| 262332a7c9 | |||
| 8b1709b8f3 | |||
| aee33d8b4b | |||
| 83f03976ea | |||
| ffcd83e3a8 | |||
| 9a522946a5 | |||
| 268d029584 | |||
| 85471d0587 | |||
| 96a1a0dec5 | |||
| 40ac055d11 | |||
| c9a6f4282a | |||
| 6ed6c08ace | |||
| e4c57a9b61 | |||
| b0d8a667a1 | |||
| 9c9ee22c2b | |||
| 639dce6282 | |||
| 8e65834c44 | |||
| 64db939e4a | |||
| 3d83f869d9 | |||
| 088a653318 | |||
| bdb1a81a39 | |||
| c2e7b6341c | |||
| e75556bc7b | |||
| d3d40983d6 | |||
| 32adf77b22 | |||
| 1301c7e95d | |||
| 1a057654b2 | |||
| ca3440cb42 | |||
| 48b22292ff | |||
| e0faaa4807 | |||
| 2e4944198d | |||
| 38a1caefb8 | |||
| e731a0a164 | |||
| 0f2efdbe97 | |||
| feeeab1761 | |||
| b4cf471021 | |||
| 82751141ac | |||
| 9f43ee3304 | |||
| 614c7b0f8e | |||
| cc84533d85 | |||
| 6faf61ba40 | |||
| 80a5019534 | |||
| 03bd02a627 | |||
| f16aa4a9b5 | |||
| a3c9e8d4fc | |||
| 3814f12b67 | |||
| ceb881ab05 | |||
| 871464811c |
@@ -24,6 +24,10 @@ buildSrc/build
|
||||
/src/asciidoc/build
|
||||
target/
|
||||
|
||||
# Projects not in this branch
|
||||
integration-tests/
|
||||
spring-core/kotlin-coroutines/
|
||||
|
||||
# Eclipse artifacts, including WTP generated manifests
|
||||
.classpath
|
||||
.project
|
||||
|
||||
+11
-11
@@ -28,24 +28,24 @@ ext {
|
||||
!it.name.equals("spring-build-src") && !it.name.equals("spring-framework-bom")
|
||||
}
|
||||
|
||||
aspectjVersion = "1.9.4"
|
||||
aspectjVersion = "1.9.5"
|
||||
freemarkerVersion = "2.3.28"
|
||||
groovyVersion = "2.5.8"
|
||||
groovyVersion = "2.5.9"
|
||||
hsqldbVersion = "2.4.1"
|
||||
jackson2Version = "2.9.9"
|
||||
jettyVersion = "9.4.21.v20190926"
|
||||
jettyVersion = "9.4.26.v20200117"
|
||||
junit5Version = "5.3.2"
|
||||
kotlinVersion = "1.2.71"
|
||||
log4jVersion = "2.11.2"
|
||||
nettyVersion = "4.1.43.Final"
|
||||
reactorVersion = "Californium-SR13"
|
||||
nettyVersion = "4.1.45.Final"
|
||||
reactorVersion = "Californium-SR16"
|
||||
rxjavaVersion = "1.3.8"
|
||||
rxjavaAdapterVersion = "1.2.1"
|
||||
rxjava2Version = "2.2.12"
|
||||
slf4jVersion = "1.7.28" // spring-jcl + consistent 3rd party deps
|
||||
rxjava2Version = "2.2.18"
|
||||
slf4jVersion = "1.7.30" // spring-jcl + consistent 3rd party deps
|
||||
tiles3Version = "3.0.8"
|
||||
tomcatVersion = "9.0.26"
|
||||
undertowVersion = "2.0.26.Final"
|
||||
tomcatVersion = "9.0.31"
|
||||
undertowVersion = "2.0.29.Final"
|
||||
|
||||
gradleScriptDir = "${rootProject.projectDir}/gradle"
|
||||
withoutJclOverSlf4j = {
|
||||
@@ -142,7 +142,7 @@ configure(allprojects) { project ->
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
toolVersion = "8.24"
|
||||
toolVersion = "8.29"
|
||||
configDir = rootProject.file("src/checkstyle")
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ configure(allprojects) { project ->
|
||||
"https://tiles.apache.org/tiles-request/apidocs/",
|
||||
"https://tiles.apache.org/framework/apidocs/",
|
||||
"https://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
|
||||
"https://www.ehcache.org/apidocs/2.10.4",
|
||||
"https://www.ehcache.org/apidocs/2.10.4/",
|
||||
"https://www.quartz-scheduler.org/api/2.3.0/",
|
||||
"https://fasterxml.github.io/jackson-core/javadoc/2.9/",
|
||||
"https://fasterxml.github.io/jackson-databind/javadoc/2.9/",
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
version=5.1.11.BUILD-SNAPSHOT
|
||||
version=5.1.14.RELEASE
|
||||
|
||||
+2
-2
@@ -149,14 +149,14 @@ task schemaZip(type: Zip) {
|
||||
def Properties schemas = new Properties();
|
||||
|
||||
subproject.sourceSets.main.resources.find {
|
||||
it.path.endsWith("META-INF/spring.schemas")
|
||||
(it.path.endsWith("META-INF/spring.schemas") || it.path.endsWith("META-INF\\spring.schemas"))
|
||||
}?.withInputStream { schemas.load(it) }
|
||||
|
||||
for (def key : schemas.keySet()) {
|
||||
def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1')
|
||||
assert shortName != key
|
||||
File xsdFile = subproject.sourceSets.main.resources.find {
|
||||
it.path.endsWith(schemas.get(key))
|
||||
(it.path.endsWith(schemas.get(key)) || it.path.endsWith(schemas.get(key).replaceAll('\\/','\\\\')))
|
||||
}
|
||||
assert xsdFile != null
|
||||
into (shortName) {
|
||||
|
||||
@@ -4,6 +4,6 @@ dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.apache.commons:commons-pool2:2.6.0")
|
||||
optional("org.apache.commons:commons-pool2:2.6.2")
|
||||
optional("com.jamonapi:jamon:2.81")
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,6 +37,7 @@ import org.springframework.scheduling.config.TaskManagementConfigUtils;
|
||||
* @see org.springframework.scheduling.annotation.ProxyAsyncConfiguration
|
||||
*/
|
||||
@Configuration
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public class AspectJAsyncConfiguration extends AbstractAsyncConfiguration {
|
||||
|
||||
@Bean(name = TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,6 +36,7 @@ import org.springframework.transaction.config.TransactionManagementConfigUtils;
|
||||
* @see TransactionManagementConfigurationSelector
|
||||
*/
|
||||
@Configuration
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public class AspectJJtaTransactionManagementConfiguration extends AspectJTransactionManagementConfiguration {
|
||||
|
||||
@Bean(name = TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_BEAN_NAME)
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,6 +38,7 @@ import org.springframework.transaction.config.TransactionManagementConfigUtils;
|
||||
* @see AspectJJtaTransactionManagementConfiguration
|
||||
*/
|
||||
@Configuration
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public class AspectJTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
|
||||
|
||||
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ASPECT_BEAN_NAME)
|
||||
|
||||
@@ -9,7 +9,7 @@ dependencies {
|
||||
optional("org.codehaus.groovy:groovy-xml:${groovyVersion}")
|
||||
optional("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
|
||||
optional("org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
|
||||
testCompile("javax.annotation:javax.annotation-api:1.3.2")
|
||||
}
|
||||
|
||||
// This module does joint compilation for Java and Groovy code with the compileGroovy task.
|
||||
|
||||
+4
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,9 +43,9 @@ import org.springframework.util.StringUtils;
|
||||
* Internal class that caches JavaBeans {@link java.beans.PropertyDescriptor}
|
||||
* information for a Java class. Not intended for direct use by application code.
|
||||
*
|
||||
* <p>Necessary for own caching of descriptors within the application's
|
||||
* ClassLoader, rather than rely on the JDK's system-wide BeanInfo cache
|
||||
* (in order to avoid leaks on ClassLoader shutdown).
|
||||
* <p>Necessary for Spring's own caching of bean descriptors within the application
|
||||
* {@link ClassLoader}, rather than relying on the JDK's system-wide {@link BeanInfo}
|
||||
* cache (in order to avoid leaks on individual application shutdown in a shared JVM).
|
||||
*
|
||||
* <p>Information is cached statically, so we don't need to create new
|
||||
* objects of this class for every JavaBean we manipulate. Hence, this class
|
||||
@@ -163,7 +163,6 @@ public final class CachedIntrospectionResults {
|
||||
* @return the corresponding CachedIntrospectionResults
|
||||
* @throws BeansException in case of introspection failure
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static CachedIntrospectionResults forClass(Class<?> beanClass) throws BeansException {
|
||||
CachedIntrospectionResults results = strongClassCache.get(beanClass);
|
||||
if (results != null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -41,8 +41,8 @@ import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Decorator for a standard {@link BeanInfo} object, e.g. as created by
|
||||
* {@link Introspector#getBeanInfo(Class)}, designed to discover and register static
|
||||
* and/or non-void returning setter methods. For example:
|
||||
* {@link Introspector#getBeanInfo(Class)}, designed to discover and register
|
||||
* static and/or non-void returning setter methods. For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* public class Bean {
|
||||
@@ -145,11 +145,10 @@ class ExtendedBeanInfo implements BeanInfo {
|
||||
|
||||
public static boolean isCandidateWriteMethod(Method method) {
|
||||
String methodName = method.getName();
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
int nParams = parameterTypes.length;
|
||||
int nParams = method.getParameterCount();
|
||||
return (methodName.length() > 3 && methodName.startsWith("set") && Modifier.isPublic(method.getModifiers()) &&
|
||||
(!void.class.isAssignableFrom(method.getReturnType()) || Modifier.isStatic(method.getModifiers())) &&
|
||||
(nParams == 1 || (nParams == 2 && int.class == parameterTypes[0])));
|
||||
(nParams == 1 || (nParams == 2 && int.class == method.getParameterTypes()[0])));
|
||||
}
|
||||
|
||||
private void handleCandidateWriteMethod(Method method) throws IntrospectionException {
|
||||
@@ -209,7 +208,7 @@ class ExtendedBeanInfo implements BeanInfo {
|
||||
}
|
||||
|
||||
private String propertyNameFor(Method method) {
|
||||
return Introspector.decapitalize(method.getName().substring(3, method.getName().length()));
|
||||
return Introspector.decapitalize(method.getName().substring(3));
|
||||
}
|
||||
|
||||
|
||||
@@ -488,7 +487,7 @@ class ExtendedBeanInfo implements BeanInfo {
|
||||
}
|
||||
|
||||
/*
|
||||
* See java.beans.IndexedPropertyDescriptor#equals(java.lang.Object)
|
||||
* See java.beans.IndexedPropertyDescriptor#equals
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
@@ -535,11 +534,13 @@ class ExtendedBeanInfo implements BeanInfo {
|
||||
public int compare(PropertyDescriptor desc1, PropertyDescriptor desc2) {
|
||||
String left = desc1.getName();
|
||||
String right = desc2.getName();
|
||||
byte[] leftBytes = left.getBytes();
|
||||
byte[] rightBytes = right.getBytes();
|
||||
for (int i = 0; i < left.length(); i++) {
|
||||
if (right.length() == i) {
|
||||
return 1;
|
||||
}
|
||||
int result = left.getBytes()[i] - right.getBytes()[i];
|
||||
int result = leftBytes[i] - rightBytes[i];
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -66,8 +66,7 @@ abstract class PropertyDescriptorUtils {
|
||||
Class<?> propertyType = null;
|
||||
|
||||
if (readMethod != null) {
|
||||
Class<?>[] params = readMethod.getParameterTypes();
|
||||
if (params.length != 0) {
|
||||
if (readMethod.getParameterCount() != 0) {
|
||||
throw new IntrospectionException("Bad read method arg count: " + readMethod);
|
||||
}
|
||||
propertyType = readMethod.getReturnType();
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -373,7 +373,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
|
||||
/**
|
||||
* Determine the name of the wrapped parameter/field.
|
||||
* @return the declared name (never {@code null})
|
||||
* @return the declared name (may be {@code null} if unresolvable)
|
||||
*/
|
||||
@Nullable
|
||||
public String getDependencyName() {
|
||||
|
||||
+45
-31
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -182,10 +182,12 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setMetaClass(MetaClass metaClass) {
|
||||
this.metaClass = metaClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaClass getMetaClass() {
|
||||
return this.metaClass;
|
||||
}
|
||||
@@ -216,6 +218,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
* @return the number of bean definitions found
|
||||
* @throws BeanDefinitionStoreException in case of loading or parsing errors
|
||||
*/
|
||||
@Override
|
||||
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
|
||||
return loadBeanDefinitions(new EncodedResource(resource));
|
||||
}
|
||||
@@ -240,10 +243,11 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
logger.trace("Loading Groovy bean definitions from " + encodedResource);
|
||||
}
|
||||
|
||||
Closure beans = new Closure(this) {
|
||||
@SuppressWarnings("serial")
|
||||
Closure<Object> beans = new Closure<Object>(this) {
|
||||
@Override
|
||||
public Object call(Object[] args) {
|
||||
invokeBeanDefiningClosure((Closure) args[0]);
|
||||
public Object call(Object... args) {
|
||||
invokeBeanDefiningClosure((Closure<?>) args[0]);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@@ -285,7 +289,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
* @param closure the block or closure
|
||||
* @return this {@code GroovyBeanDefinitionReader} instance
|
||||
*/
|
||||
public GroovyBeanDefinitionReader beans(Closure closure) {
|
||||
public GroovyBeanDefinitionReader beans(Closure<?> closure) {
|
||||
return invokeBeanDefiningClosure(closure);
|
||||
}
|
||||
|
||||
@@ -309,25 +313,22 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
public AbstractBeanDefinition bean(Class<?> type, Object...args) {
|
||||
GroovyBeanDefinitionWrapper current = this.currentBeanDefinition;
|
||||
try {
|
||||
Closure callable = null;
|
||||
Collection constructorArgs = null;
|
||||
Closure<?> callable = null;
|
||||
Collection<Object> constructorArgs = null;
|
||||
if (!ObjectUtils.isEmpty(args)) {
|
||||
int index = args.length;
|
||||
Object lastArg = args[index - 1];
|
||||
if (lastArg instanceof Closure) {
|
||||
callable = (Closure) lastArg;
|
||||
if (lastArg instanceof Closure<?>) {
|
||||
callable = (Closure<?>) lastArg;
|
||||
index--;
|
||||
}
|
||||
if (index > -1) {
|
||||
constructorArgs = resolveConstructorArguments(args, 0, index);
|
||||
}
|
||||
constructorArgs = resolveConstructorArguments(args, 0, index);
|
||||
}
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(null, type, constructorArgs);
|
||||
if (callable != null) {
|
||||
callable.call(this.currentBeanDefinition);
|
||||
}
|
||||
return this.currentBeanDefinition.getBeanDefinition();
|
||||
|
||||
}
|
||||
finally {
|
||||
this.currentBeanDefinition = current;
|
||||
@@ -373,10 +374,11 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
* This method overrides method invocation to create beans for each method name that
|
||||
* takes a class argument.
|
||||
*/
|
||||
@Override
|
||||
public Object invokeMethod(String name, Object arg) {
|
||||
Object[] args = (Object[])arg;
|
||||
if ("beans".equals(name) && args.length == 1 && args[0] instanceof Closure) {
|
||||
return beans((Closure) args[0]);
|
||||
return beans((Closure<?>) args[0]);
|
||||
}
|
||||
else if ("ref".equals(name)) {
|
||||
String refName;
|
||||
@@ -429,10 +431,10 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
private void finalizeDeferredProperties() {
|
||||
for (DeferredProperty dp : this.deferredProperties.values()) {
|
||||
if (dp.value instanceof List) {
|
||||
dp.value = manageListIfNecessary((List) dp.value);
|
||||
dp.value = manageListIfNecessary((List<?>) dp.value);
|
||||
}
|
||||
else if (dp.value instanceof Map) {
|
||||
dp.value = manageMapIfNecessary((Map) dp.value);
|
||||
dp.value = manageMapIfNecessary((Map<?, ?>) dp.value);
|
||||
}
|
||||
dp.apply();
|
||||
}
|
||||
@@ -444,7 +446,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
* @param callable the closure argument
|
||||
* @return this {@code GroovyBeanDefinitionReader} instance
|
||||
*/
|
||||
protected GroovyBeanDefinitionReader invokeBeanDefiningClosure(Closure callable) {
|
||||
protected GroovyBeanDefinitionReader invokeBeanDefiningClosure(Closure<?> callable) {
|
||||
callable.setDelegate(this);
|
||||
callable.call();
|
||||
finalizeDeferredProperties();
|
||||
@@ -483,9 +485,10 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
else if (args[0] instanceof Map) {
|
||||
// named constructor arguments
|
||||
if (args.length > 1 && args[1] instanceof Class) {
|
||||
List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length);
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, (Class)args[1], constructorArgs);
|
||||
Map namedArgs = (Map)args[0];
|
||||
List<Object> constructorArgs =
|
||||
resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length);
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, (Class<?>) args[1], constructorArgs);
|
||||
Map<?, ?> namedArgs = (Map<?, ?>) args[0];
|
||||
for (Object o : namedArgs.keySet()) {
|
||||
String propName = (String) o;
|
||||
setProperty(propName, namedArgs.get(propName));
|
||||
@@ -494,8 +497,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
// factory method syntax
|
||||
else {
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName);
|
||||
//First arg is the map containing factoryBean : factoryMethod
|
||||
Map.Entry factoryBeanEntry = (Map.Entry) ((Map) args[0]).entrySet().iterator().next();
|
||||
// First arg is the map containing factoryBean : factoryMethod
|
||||
Map.Entry<?, ?> factoryBeanEntry = ((Map<?, ?>) args[0]).entrySet().iterator().next();
|
||||
// If we have a closure body, that will be the last argument.
|
||||
// In between are the constructor args
|
||||
int constructorArgsTest = (hasClosureArgument ? 2 : 1);
|
||||
@@ -519,12 +522,13 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
this.currentBeanDefinition.getBeanDefinition().setAbstract(true);
|
||||
}
|
||||
else {
|
||||
List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length - 1 : args.length);
|
||||
List<Object> constructorArgs =
|
||||
resolveConstructorArguments(args, 0, hasClosureArgument ? args.length - 1 : args.length);
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, null, constructorArgs);
|
||||
}
|
||||
|
||||
if (hasClosureArgument) {
|
||||
Closure callable = (Closure) args[args.length - 1];
|
||||
Closure<?> callable = (Closure<?>) args[args.length - 1];
|
||||
callable.setDelegate(this);
|
||||
callable.setResolveStrategy(Closure.DELEGATE_FIRST);
|
||||
callable.call(this.currentBeanDefinition);
|
||||
@@ -544,10 +548,10 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
constructorArgs[i] = constructorArgs[i].toString();
|
||||
}
|
||||
else if (constructorArgs[i] instanceof List) {
|
||||
constructorArgs[i] = manageListIfNecessary((List) constructorArgs[i]);
|
||||
constructorArgs[i] = manageListIfNecessary((List<?>) constructorArgs[i]);
|
||||
}
|
||||
else if (constructorArgs[i] instanceof Map){
|
||||
constructorArgs[i] = manageMapIfNecessary((Map) constructorArgs[i]);
|
||||
constructorArgs[i] = manageMapIfNecessary((Map<?, ?>) constructorArgs[i]);
|
||||
}
|
||||
}
|
||||
return Arrays.asList(constructorArgs);
|
||||
@@ -601,6 +605,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
* This method overrides property setting in the scope of the {@code GroovyBeanDefinitionReader}
|
||||
* to set properties on the current bean definition.
|
||||
*/
|
||||
@Override
|
||||
public void setProperty(String name, Object value) {
|
||||
if (this.currentBeanDefinition != null) {
|
||||
applyPropertyToBeanDefinition(name, value);
|
||||
@@ -617,7 +622,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
else if (value instanceof Closure) {
|
||||
GroovyBeanDefinitionWrapper current = this.currentBeanDefinition;
|
||||
try {
|
||||
Closure callable = (Closure) value;
|
||||
Closure<?> callable = (Closure<?>) value;
|
||||
Class<?> parameterType = callable.getParameterTypes()[0];
|
||||
if (Object.class == parameterType) {
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper("");
|
||||
@@ -647,6 +652,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
* properties from the {@code GroovyBeanDefinitionReader} itself
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
Binding binding = getBinding();
|
||||
if (binding != null && binding.hasVariable(name)) {
|
||||
@@ -690,8 +696,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
private GroovyDynamicElementReader createDynamicElementReader(String namespace) {
|
||||
XmlReaderContext readerContext = this.groovyDslXmlBeanDefinitionReader.createReaderContext(new DescriptiveResource(
|
||||
"Groovy"));
|
||||
XmlReaderContext readerContext = this.groovyDslXmlBeanDefinitionReader.createReaderContext(
|
||||
new DescriptiveResource("Groovy"));
|
||||
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
|
||||
boolean decorating = (this.currentBeanDefinition != null);
|
||||
if (!decorating) {
|
||||
@@ -749,10 +755,12 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
this.metaClass = InvokerHelper.getMetaClass(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaClass getMetaClass() {
|
||||
return this.metaClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String property) {
|
||||
if (property.equals("beanName")) {
|
||||
return getBeanName();
|
||||
@@ -769,14 +777,17 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invokeMethod(String name, Object args) {
|
||||
return this.metaClass.invokeMethod(this, name, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMetaClass(MetaClass metaClass) {
|
||||
this.metaClass = metaClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(String property, Object newValue) {
|
||||
if (!addDeferredProperty(property, newValue)) {
|
||||
this.beanDefinition.getBeanDefinition().getPropertyValues().add(property, newValue);
|
||||
@@ -785,7 +796,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
|
||||
|
||||
/**
|
||||
* Wraps a bean definition property an ensures that any RuntimeBeanReference
|
||||
* Wraps a bean definition property and ensures that any RuntimeBeanReference
|
||||
* additions to it are deferred for resolution later.
|
||||
*/
|
||||
private class GroovyPropertyValue extends GroovyObjectSupport {
|
||||
@@ -799,18 +810,21 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
this.propertyValue = propertyValue;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void leftShift(Object value) {
|
||||
InvokerHelper.invokeMethod(this.propertyValue, "leftShift", value);
|
||||
updateDeferredProperties(value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public boolean add(Object value) {
|
||||
boolean retVal = (Boolean) InvokerHelper.invokeMethod(this.propertyValue, "add", value);
|
||||
updateDeferredProperties(value);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public boolean addAll(Collection values) {
|
||||
@SuppressWarnings("unused")
|
||||
public boolean addAll(Collection<?> values) {
|
||||
boolean retVal = (Boolean) InvokerHelper.invokeMethod(this.propertyValue, "addAll", values);
|
||||
for (Object value : values) {
|
||||
updateDeferredProperties(value);
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -196,7 +196,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
|
||||
// constructorArgs
|
||||
else if (CONSTRUCTOR_ARGS.equals(property) && newValue instanceof List) {
|
||||
ConstructorArgumentValues cav = new ConstructorArgumentValues();
|
||||
List args = (List) newValue;
|
||||
List<?> args = (List<?>) newValue;
|
||||
for (Object arg : args) {
|
||||
cav.addGenericArgumentValue(arg);
|
||||
}
|
||||
|
||||
+6
-13
@@ -645,7 +645,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
@Nullable
|
||||
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
|
||||
Class<?> targetType = determineTargetType(beanName, mbd, typesToMatch);
|
||||
|
||||
// Apply SmartInstantiationAwareBeanPostProcessors to predict the
|
||||
// eventual type after a before-instantiation shortcut.
|
||||
if (targetType != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
|
||||
@@ -1364,34 +1363,28 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
|
||||
// state of the bean before properties are set. This can be used, for example,
|
||||
// to support styles of field injection.
|
||||
boolean continueWithPropertyPopulation = true;
|
||||
|
||||
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
|
||||
for (BeanPostProcessor bp : getBeanPostProcessors()) {
|
||||
if (bp instanceof InstantiationAwareBeanPostProcessor) {
|
||||
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
|
||||
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
|
||||
continueWithPropertyPopulation = false;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!continueWithPropertyPopulation) {
|
||||
return;
|
||||
}
|
||||
|
||||
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
|
||||
|
||||
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
|
||||
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
|
||||
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
|
||||
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
|
||||
// Add property values based on autowire by name if applicable.
|
||||
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
|
||||
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
|
||||
autowireByName(beanName, mbd, bw, newPvs);
|
||||
}
|
||||
// Add property values based on autowire by type if applicable.
|
||||
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
|
||||
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
|
||||
autowireByType(beanName, mbd, bw, newPvs);
|
||||
}
|
||||
pvs = newPvs;
|
||||
@@ -1495,7 +1488,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
if (Object.class != pd.getPropertyType()) {
|
||||
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
|
||||
// Do not allow eager init for type matching in case of a prioritized post-processor.
|
||||
boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
|
||||
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
|
||||
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
|
||||
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
|
||||
if (autowiredArgument != null) {
|
||||
|
||||
+24
-24
@@ -1127,30 +1127,30 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
return false;
|
||||
}
|
||||
AbstractBeanDefinition that = (AbstractBeanDefinition) other;
|
||||
boolean rtn = ObjectUtils.nullSafeEquals(getBeanClassName(), that.getBeanClassName());
|
||||
rtn = rtn &= ObjectUtils.nullSafeEquals(this.scope, that.scope);
|
||||
rtn = rtn &= this.abstractFlag == that.abstractFlag;
|
||||
rtn = rtn &= this.lazyInit == that.lazyInit;
|
||||
rtn = rtn &= this.autowireMode == that.autowireMode;
|
||||
rtn = rtn &= this.dependencyCheck == that.dependencyCheck;
|
||||
rtn = rtn &= Arrays.equals(this.dependsOn, that.dependsOn);
|
||||
rtn = rtn &= this.autowireCandidate == that.autowireCandidate;
|
||||
rtn = rtn &= ObjectUtils.nullSafeEquals(this.qualifiers, that.qualifiers);
|
||||
rtn = rtn &= this.primary == that.primary;
|
||||
rtn = rtn &= this.nonPublicAccessAllowed == that.nonPublicAccessAllowed;
|
||||
rtn = rtn &= this.lenientConstructorResolution == that.lenientConstructorResolution;
|
||||
rtn = rtn &= ObjectUtils.nullSafeEquals(this.constructorArgumentValues, that.constructorArgumentValues);
|
||||
rtn = rtn &= ObjectUtils.nullSafeEquals(this.propertyValues, that.propertyValues);
|
||||
rtn = rtn &= ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides);
|
||||
rtn = rtn &= ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName);
|
||||
rtn = rtn &= ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName);
|
||||
rtn = rtn &= ObjectUtils.nullSafeEquals(this.initMethodName, that.initMethodName);
|
||||
rtn = rtn &= this.enforceInitMethod == that.enforceInitMethod;
|
||||
rtn = rtn &= ObjectUtils.nullSafeEquals(this.destroyMethodName, that.destroyMethodName);
|
||||
rtn = rtn &= this.enforceDestroyMethod == that.enforceDestroyMethod;
|
||||
rtn = rtn &= this.synthetic == that.synthetic;
|
||||
rtn = rtn &= this.role == that.role;
|
||||
return rtn && super.equals(other);
|
||||
return (ObjectUtils.nullSafeEquals(getBeanClassName(), that.getBeanClassName()) &&
|
||||
ObjectUtils.nullSafeEquals(this.scope, that.scope) &&
|
||||
this.abstractFlag == that.abstractFlag &&
|
||||
this.lazyInit == that.lazyInit &&
|
||||
this.autowireMode == that.autowireMode &&
|
||||
this.dependencyCheck == that.dependencyCheck &&
|
||||
Arrays.equals(this.dependsOn, that.dependsOn) &&
|
||||
this.autowireCandidate == that.autowireCandidate &&
|
||||
ObjectUtils.nullSafeEquals(this.qualifiers, that.qualifiers) &&
|
||||
this.primary == that.primary &&
|
||||
this.nonPublicAccessAllowed == that.nonPublicAccessAllowed &&
|
||||
this.lenientConstructorResolution == that.lenientConstructorResolution &&
|
||||
ObjectUtils.nullSafeEquals(this.constructorArgumentValues, that.constructorArgumentValues) &&
|
||||
ObjectUtils.nullSafeEquals(this.propertyValues, that.propertyValues) &&
|
||||
ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides) &&
|
||||
ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName) &&
|
||||
ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName) &&
|
||||
ObjectUtils.nullSafeEquals(this.initMethodName, that.initMethodName) &&
|
||||
this.enforceInitMethod == that.enforceInitMethod &&
|
||||
ObjectUtils.nullSafeEquals(this.destroyMethodName, that.destroyMethodName) &&
|
||||
this.enforceDestroyMethod == that.enforceDestroyMethod &&
|
||||
this.synthetic == that.synthetic &&
|
||||
this.role == that.role &&
|
||||
super.equals(other));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+9
@@ -302,6 +302,15 @@ public final class BeanDefinitionBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this bean is a primary autowire candidate.
|
||||
* @since 5.1.11
|
||||
*/
|
||||
public BeanDefinitionBuilder setPrimary(boolean primary) {
|
||||
this.beanDefinition.setPrimary(primary);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the role of this definition.
|
||||
*/
|
||||
|
||||
+1
@@ -612,6 +612,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
* should <i>not</i> have their own mutexes involved in singleton creation,
|
||||
* to avoid the potential for deadlocks in lazy-init situations.
|
||||
*/
|
||||
@Override
|
||||
public final Object getSingletonMutex() {
|
||||
return this.singletonObjects;
|
||||
}
|
||||
|
||||
+3
-3
@@ -311,9 +311,9 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
* assuming a "force" parameter), else logging an error.
|
||||
*/
|
||||
private void invokeCustomDestroyMethod(final Method destroyMethod) {
|
||||
Class<?>[] paramTypes = destroyMethod.getParameterTypes();
|
||||
final Object[] args = new Object[paramTypes.length];
|
||||
if (paramTypes.length == 1) {
|
||||
int paramCount = destroyMethod.getParameterCount();
|
||||
final Object[] args = new Object[paramCount];
|
||||
if (paramCount == 1) {
|
||||
args[0] = Boolean.TRUE;
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -146,8 +146,9 @@ public class ArgumentConvertingMethodInvoker extends MethodInvoker {
|
||||
for (Method candidate : candidates) {
|
||||
if (candidate.getName().equals(targetMethod)) {
|
||||
// Check if the inspected method has the correct number of parameters.
|
||||
Class<?>[] paramTypes = candidate.getParameterTypes();
|
||||
if (paramTypes.length == argCount) {
|
||||
int parameterCount = candidate.getParameterCount();
|
||||
if (parameterCount == argCount) {
|
||||
Class<?>[] paramTypes = candidate.getParameterTypes();
|
||||
Object[] convertedArguments = new Object[argCount];
|
||||
boolean match = true;
|
||||
for (int j = 0; j < argCount && match; j++) {
|
||||
|
||||
@@ -16,7 +16,7 @@ dependencies {
|
||||
optional("org.freemarker:freemarker:${freemarkerVersion}")
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
testCompile("org.hibernate:hibernate-validator:6.0.17.Final")
|
||||
testCompile("org.hibernate:hibernate-validator:6.0.18.Final")
|
||||
testCompile("javax.annotation:javax.annotation-api:1.3.2")
|
||||
testRuntime("org.ehcache:jcache:1.0.1")
|
||||
testRuntime("org.ehcache:ehcache:3.4.0")
|
||||
|
||||
+1
@@ -88,6 +88,7 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial
|
||||
return this.cacheOperationSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
getCacheOperationSource();
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -110,7 +110,7 @@ public class LocalDataSourceJobStore extends JobStoreCMT {
|
||||
public void shutdown() {
|
||||
// Do nothing - a Spring-managed DataSource has its own lifecycle.
|
||||
}
|
||||
/* Quartz 2.2 initialize method */
|
||||
@Override
|
||||
public void initialize() {
|
||||
// Do nothing - a Spring-managed DataSource has its own lifecycle.
|
||||
}
|
||||
@@ -138,7 +138,7 @@ public class LocalDataSourceJobStore extends JobStoreCMT {
|
||||
public void shutdown() {
|
||||
// Do nothing - a Spring-managed DataSource has its own lifecycle.
|
||||
}
|
||||
/* Quartz 2.2 initialize method */
|
||||
@Override
|
||||
public void initialize() {
|
||||
// Do nothing - a Spring-managed DataSource has its own lifecycle.
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -82,6 +82,7 @@ public class ResourceLoaderClassLoadHelper implements ClassLoadHelper {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> Class<? extends T> loadClass(String name, Class<T> clazz) throws ClassNotFoundException {
|
||||
return (Class<? extends T>) loadClass(name);
|
||||
}
|
||||
|
||||
@@ -19,16 +19,16 @@ dependencies {
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.codehaus.groovy:groovy:${groovyVersion}")
|
||||
optional("org.beanshell:bsh:2.0b5")
|
||||
optional("joda-time:joda-time:2.10.4")
|
||||
optional("joda-time:joda-time:2.10.5")
|
||||
optional("org.hibernate:hibernate-validator:5.4.3.Final")
|
||||
optional("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
|
||||
optional("org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}")
|
||||
testCompile("org.codehaus.groovy:groovy-jsr223:${groovyVersion}")
|
||||
testCompile("org.codehaus.groovy:groovy-test:${groovyVersion}")
|
||||
testCompile("org.codehaus.groovy:groovy-xml:${groovyVersion}")
|
||||
testCompile("org.apache.commons:commons-pool2:2.6.0")
|
||||
testCompile("org.apache.commons:commons-pool2:2.6.2")
|
||||
testCompile("javax.inject:javax.inject-tck:1")
|
||||
testCompile("org.awaitility:awaitility:3.1.3")
|
||||
testCompile("org.awaitility:awaitility:3.1.6")
|
||||
testRuntime("javax.xml.bind:jaxb-api:2.3.1")
|
||||
testRuntime("org.glassfish:javax.el:3.0.1-b08")
|
||||
testRuntime("org.javamoney:moneta:1.3")
|
||||
|
||||
+3
-1
@@ -32,7 +32,9 @@ import org.springframework.util.StringUtils;
|
||||
@SuppressWarnings("serial")
|
||||
public class SimpleKey implements Serializable {
|
||||
|
||||
/** An empty key. */
|
||||
/**
|
||||
* An empty key.
|
||||
*/
|
||||
public static final SimpleKey EMPTY = new SimpleKey();
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,19 +17,21 @@
|
||||
package org.springframework.context;
|
||||
|
||||
/**
|
||||
* An extension of the {@link Lifecycle} interface for those objects that require to
|
||||
* be started upon ApplicationContext refresh and/or shutdown in a particular order.
|
||||
* The {@link #isAutoStartup()} return value indicates whether this object should
|
||||
* An extension of the {@link Lifecycle} interface for those objects that require
|
||||
* to be started upon {@code ApplicationContext} refresh and/or shutdown in a
|
||||
* particular order.
|
||||
*
|
||||
* <p>The {@link #isAutoStartup()} return value indicates whether this object should
|
||||
* be started at the time of a context refresh. The callback-accepting
|
||||
* {@link #stop(Runnable)} method is useful for objects that have an asynchronous
|
||||
* shutdown process. Any implementation of this interface <i>must</i> invoke the
|
||||
* callback's {@code run()} method upon shutdown completion to avoid unnecessary
|
||||
* delays in the overall ApplicationContext shutdown.
|
||||
* delays in the overall {@code ApplicationContext} shutdown.
|
||||
*
|
||||
* <p>This interface extends {@link Phased}, and the {@link #getPhase()} method's
|
||||
* return value indicates the phase within which this Lifecycle component should
|
||||
* be started and stopped. The startup process begins with the <i>lowest</i> phase
|
||||
* value and ends with the <i>highest</i> phase value ({@code Integer.MIN_VALUE}
|
||||
* return value indicates the phase within which this {@code Lifecycle} component
|
||||
* should be started and stopped. The startup process begins with the <i>lowest</i>
|
||||
* phase value and ends with the <i>highest</i> phase value ({@code Integer.MIN_VALUE}
|
||||
* is the lowest possible, and {@code Integer.MAX_VALUE} is the highest possible).
|
||||
* The shutdown process will apply the reverse order. Any components with the
|
||||
* same value will be arbitrarily ordered within the same phase.
|
||||
@@ -44,9 +46,11 @@ package org.springframework.context;
|
||||
*
|
||||
* <p>Any {@code Lifecycle} components within the context that do not also
|
||||
* implement {@code SmartLifecycle} will be treated as if they have a phase
|
||||
* value of 0. That way a {@code SmartLifecycle} implementation may start
|
||||
* before those {@code Lifecycle} components if it has a negative phase value,
|
||||
* or it may start after those components if it has a positive phase value.
|
||||
* value of {@code 0}. This allows a {@code SmartLifecycle} component to start
|
||||
* before those {@code Lifecycle} components if the {@code SmartLifecycle}
|
||||
* component has a negative phase value, or the {@code SmartLifecycle} component
|
||||
* may start after those {@code Lifecycle} components if the {@code SmartLifecycle}
|
||||
* component has a positive phase value.
|
||||
*
|
||||
* <p>Note that, due to the auto-startup support in {@code SmartLifecycle}, a
|
||||
* {@code SmartLifecycle} bean instance will usually get initialized on startup
|
||||
@@ -55,6 +59,7 @@ package org.springframework.context;
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
* @see LifecycleProcessor
|
||||
* @see ConfigurableApplicationContext
|
||||
@@ -63,9 +68,10 @@ public interface SmartLifecycle extends Lifecycle, Phased {
|
||||
|
||||
/**
|
||||
* The default phase for {@code SmartLifecycle}: {@code Integer.MAX_VALUE}.
|
||||
* <p>This is different from the common phase 0 associated with regular
|
||||
* <p>This is different from the common phase {@code 0} associated with regular
|
||||
* {@link Lifecycle} implementations, putting the typically auto-started
|
||||
* {@code SmartLifecycle} beans into a separate later shutdown phase.
|
||||
* {@code SmartLifecycle} beans into a later startup phase and an earlier
|
||||
* shutdown phase.
|
||||
* @since 5.1
|
||||
* @see #getPhase()
|
||||
* @see org.springframework.context.support.DefaultLifecycleProcessor#getPhase(Lifecycle)
|
||||
@@ -115,7 +121,8 @@ public interface SmartLifecycle extends Lifecycle, Phased {
|
||||
/**
|
||||
* Return the phase that this lifecycle object is supposed to run in.
|
||||
* <p>The default implementation returns {@link #DEFAULT_PHASE} in order to
|
||||
* let stop callbacks execute after regular {@code Lifecycle} implementations.
|
||||
* let {@code stop()} callbacks execute after regular {@code Lifecycle}
|
||||
* implementations.
|
||||
* @see #isAutoStartup()
|
||||
* @see #start()
|
||||
* @see #stop(Runnable)
|
||||
|
||||
+5
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -748,8 +748,7 @@ class ConfigurationClassParser {
|
||||
* @param importSelector the selector to handle
|
||||
*/
|
||||
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
|
||||
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(
|
||||
configClass, importSelector);
|
||||
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
|
||||
if (this.deferredImportSelectors == null) {
|
||||
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
|
||||
handler.register(holder);
|
||||
@@ -775,7 +774,6 @@ class ConfigurationClassParser {
|
||||
this.deferredImportSelectors = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -786,8 +784,7 @@ class ConfigurationClassParser {
|
||||
private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
|
||||
|
||||
public void register(DeferredImportSelectorHolder deferredImport) {
|
||||
Class<? extends Group> group = deferredImport.getImportSelector()
|
||||
.getImportGroup();
|
||||
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
|
||||
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
|
||||
(group != null ? group : deferredImport),
|
||||
key -> new DeferredImportSelectorGrouping(createGroup(group)));
|
||||
@@ -799,8 +796,7 @@ class ConfigurationClassParser {
|
||||
public void processGroupImports() {
|
||||
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
|
||||
grouping.getImports().forEach(entry -> {
|
||||
ConfigurationClass configurationClass = this.configurationClasses.get(
|
||||
entry.getMetadata());
|
||||
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
|
||||
try {
|
||||
processImports(configurationClass, asSourceClass(configurationClass),
|
||||
asSourceClasses(entry.getImportClassName()), false);
|
||||
@@ -818,8 +814,7 @@ class ConfigurationClassParser {
|
||||
}
|
||||
|
||||
private Group createGroup(@Nullable Class<? extends Group> type) {
|
||||
Class<? extends Group> effectiveType = (type != null ? type
|
||||
: DefaultDeferredImportSelectorGroup.class);
|
||||
Class<? extends Group> effectiveType = (type != null ? type : DefaultDeferredImportSelectorGroup.class);
|
||||
Group group = BeanUtils.instantiateClass(effectiveType);
|
||||
ParserStrategyUtils.invokeAwareMethods(group,
|
||||
ConfigurationClassParser.this.environment,
|
||||
@@ -827,7 +822,6 @@ class ConfigurationClassParser {
|
||||
ConfigurationClassParser.this.registry);
|
||||
return group;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+10
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
@@ -53,6 +51,7 @@ public interface DeferredImportSelector extends ImportSelector {
|
||||
|
||||
/**
|
||||
* Interface used to group results from different import selectors.
|
||||
* @since 5.0
|
||||
*/
|
||||
interface Group {
|
||||
|
||||
@@ -100,7 +99,7 @@ public interface DeferredImportSelector extends ImportSelector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
@@ -108,13 +107,17 @@ public interface DeferredImportSelector extends ImportSelector {
|
||||
return false;
|
||||
}
|
||||
Entry entry = (Entry) other;
|
||||
return (Objects.equals(this.metadata, entry.metadata) &&
|
||||
Objects.equals(this.importClassName, entry.importClassName));
|
||||
return (this.metadata.equals(entry.metadata) && this.importClassName.equals(entry.importClassName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.metadata, this.importClassName);
|
||||
return (this.metadata.hashCode() * 31 + this.importClassName.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.importClassName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,6 +50,7 @@ public interface ImportSelector {
|
||||
/**
|
||||
* Select and return the names of which class(es) should be imported based on
|
||||
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
|
||||
* @return the class names, or an empty array if none
|
||||
*/
|
||||
String[] selectImports(AnnotationMetadata importingClassMetadata);
|
||||
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,6 +42,7 @@ import org.springframework.util.Assert;
|
||||
* @see ConfigurableApplicationContext#LOAD_TIME_WEAVER_BEAN_NAME
|
||||
*/
|
||||
@Configuration
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoaderAware {
|
||||
|
||||
@Nullable
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,6 +50,7 @@ import org.springframework.util.StringUtils;
|
||||
* @see EnableMBeanExport
|
||||
*/
|
||||
@Configuration
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public class MBeanExportConfiguration implements ImportAware, EnvironmentAware, BeanFactoryAware {
|
||||
|
||||
private static final String MBEAN_EXPORTER_BEAN_NAME = "mbeanExporter";
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -53,6 +53,6 @@ public enum ScopedProxyMode {
|
||||
/**
|
||||
* Create a class-based proxy (uses CGLIB).
|
||||
*/
|
||||
TARGET_CLASS;
|
||||
TARGET_CLASS
|
||||
|
||||
}
|
||||
|
||||
+7
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -160,8 +160,9 @@ public abstract class AbstractResourceBasedMessageSource extends AbstractMessage
|
||||
/**
|
||||
* Set the number of seconds to cache loaded properties files.
|
||||
* <ul>
|
||||
* <li>Default is "-1", indicating to cache forever (just like
|
||||
* {@code java.util.ResourceBundle}).
|
||||
* <li>Default is "-1", indicating to cache forever (matching the default behavior
|
||||
* of {@code java.util.ResourceBundle}). Note that this constant follows Spring
|
||||
* conventions, not {@link java.util.ResourceBundle.Control#getTimeToLive}.
|
||||
* <li>A positive number will cache loaded properties files for the given
|
||||
* number of seconds. This is essentially the interval between refresh checks.
|
||||
* Note that a refresh attempt will first check the last-modified timestamp
|
||||
@@ -184,8 +185,9 @@ public abstract class AbstractResourceBasedMessageSource extends AbstractMessage
|
||||
* Set the number of milliseconds to cache loaded properties files.
|
||||
* Note that it is common to set seconds instead: {@link #setCacheSeconds}.
|
||||
* <ul>
|
||||
* <li>Default is "-1", indicating to cache forever (just like
|
||||
* {@code java.util.ResourceBundle}).
|
||||
* <li>Default is "-1", indicating to cache forever (matching the default behavior
|
||||
* of {@code java.util.ResourceBundle}). Note that this constant follows Spring
|
||||
* conventions, not {@link java.util.ResourceBundle.Control#getTimeToLive}.
|
||||
* <li>A positive number will cache loaded properties files for the given
|
||||
* number of milliseconds. This is essentially the interval between refresh checks.
|
||||
* Note that a refresh attempt will first check the last-modified timestamp
|
||||
|
||||
+5
@@ -225,18 +225,22 @@ public class GenericGroovyApplicationContext extends GenericApplicationContext i
|
||||
|
||||
// Implementation of the GroovyObject interface
|
||||
|
||||
@Override
|
||||
public void setMetaClass(MetaClass metaClass) {
|
||||
this.metaClass = metaClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaClass getMetaClass() {
|
||||
return this.metaClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invokeMethod(String name, Object args) {
|
||||
return this.metaClass.invokeMethod(this, name, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(String property, Object newValue) {
|
||||
if (newValue instanceof BeanDefinition) {
|
||||
registerBeanDefinition(property, (BeanDefinition) newValue);
|
||||
@@ -246,6 +250,7 @@ public class GenericGroovyApplicationContext extends GenericApplicationContext i
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getProperty(String property) {
|
||||
if (containsBean(property)) {
|
||||
|
||||
+19
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -237,6 +237,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
if (mergedHolder != null) {
|
||||
return mergedHolder;
|
||||
}
|
||||
|
||||
Properties mergedProps = newProperties();
|
||||
long latestTimestamp = -1;
|
||||
String[] basenames = StringUtils.toStringArray(getBasenameSet());
|
||||
@@ -253,6 +254,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mergedHolder = new PropertiesHolder(mergedProps, latestTimestamp);
|
||||
PropertiesHolder existing = this.cachedMergedProperties.putIfAbsent(locale, mergedHolder);
|
||||
if (existing != null) {
|
||||
@@ -279,18 +281,28 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
return filenames;
|
||||
}
|
||||
}
|
||||
|
||||
// Filenames for given Locale
|
||||
List<String> filenames = new ArrayList<>(7);
|
||||
filenames.addAll(calculateFilenamesForLocale(basename, locale));
|
||||
if (isFallbackToSystemLocale() && !locale.equals(Locale.getDefault())) {
|
||||
List<String> fallbackFilenames = calculateFilenamesForLocale(basename, Locale.getDefault());
|
||||
for (String fallbackFilename : fallbackFilenames) {
|
||||
if (!filenames.contains(fallbackFilename)) {
|
||||
// Entry for fallback locale that isn't already in filenames list.
|
||||
filenames.add(fallbackFilename);
|
||||
|
||||
// Filenames for default Locale, if any
|
||||
if (isFallbackToSystemLocale()) {
|
||||
Locale defaultLocale = Locale.getDefault();
|
||||
if (!locale.equals(defaultLocale)) {
|
||||
List<String> fallbackFilenames = calculateFilenamesForLocale(basename, defaultLocale);
|
||||
for (String fallbackFilename : fallbackFilenames) {
|
||||
if (!filenames.contains(fallbackFilename)) {
|
||||
// Entry for fallback locale that isn't already in filenames list.
|
||||
filenames.add(fallbackFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filename for default bundle file
|
||||
filenames.add(basename);
|
||||
|
||||
if (localeMap == null) {
|
||||
localeMap = new ConcurrentHashMap<>();
|
||||
Map<Locale, List<String>> existing = this.cachedFilenames.putIfAbsent(basename, localeMap);
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,6 +43,7 @@ public class StaticMessageSource extends AbstractMessageSource {
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected String resolveCodeWithoutArguments(String code, Locale locale) {
|
||||
return this.messages.get(code + '_' + locale.toString());
|
||||
}
|
||||
|
||||
+1
-2
@@ -61,14 +61,13 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
|
||||
@Override
|
||||
public void registerFormatters(FormatterRegistry registry) {
|
||||
addDateConverters(registry);
|
||||
registry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory());
|
||||
|
||||
// In order to retain back compatibility we only register Date/Calendar
|
||||
// types when a user defined formatter is specified (see SPR-10105)
|
||||
if (this.dateFormatter != null) {
|
||||
registry.addFormatter(this.dateFormatter);
|
||||
registry.addFormatterForFieldType(Calendar.class, this.dateFormatter);
|
||||
}
|
||||
registry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+7
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,6 +31,7 @@ import org.springframework.format.Formatter;
|
||||
* (which is commonly used for HTTP date header values), as of Spring 4.3.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Andrei Nevedomskii
|
||||
* @since 4.0
|
||||
* @see java.time.Instant#parse
|
||||
* @see java.time.format.DateTimeFormatter#ISO_INSTANT
|
||||
@@ -40,14 +41,14 @@ public class InstantFormatter implements Formatter<Instant> {
|
||||
|
||||
@Override
|
||||
public Instant parse(String text, Locale locale) throws ParseException {
|
||||
if (text.length() > 0 && Character.isDigit(text.charAt(0))) {
|
||||
// assuming UTC instant a la "2007-12-03T10:15:30.00Z"
|
||||
return Instant.parse(text);
|
||||
}
|
||||
else {
|
||||
if (text.length() > 0 && Character.isAlphabetic(text.charAt(0))) {
|
||||
// assuming RFC-1123 value a la "Tue, 3 Jun 2008 11:05:30 GMT"
|
||||
return Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(text));
|
||||
}
|
||||
else {
|
||||
// assuming UTC instant a la "2007-12-03T10:15:30.00Z"
|
||||
return Instant.parse(text);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -207,7 +207,7 @@ public class InterfaceBasedMBeanInfoAssembler extends AbstractConfigurableMBeanI
|
||||
* configured interfaces and is public, otherwise {@code false}.
|
||||
*/
|
||||
private boolean isPublicInInterface(Method method, String beanKey) {
|
||||
return ((method.getModifiers() & Modifier.PUBLIC) > 0) && isDeclaredInInterface(method, beanKey);
|
||||
return Modifier.isPublic(method.getModifiers()) && isDeclaredInInterface(method, beanKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,6 +231,7 @@ public class InterfaceBasedMBeanInfoAssembler extends AbstractConfigurableMBeanI
|
||||
for (Class<?> ifc : ifaces) {
|
||||
for (Method ifcMethod : ifc.getMethods()) {
|
||||
if (ifcMethod.getName().equals(method.getName()) &&
|
||||
ifcMethod.getParameterCount() == method.getParameterCount() &&
|
||||
Arrays.equals(ifcMethod.getParameterTypes(), method.getParameterTypes())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,6 +42,6 @@ public enum RegistrationPolicy {
|
||||
* Registration should replace the affected MBean when attempting to register an MBean
|
||||
* under a name that already exists.
|
||||
*/
|
||||
REPLACE_EXISTING;
|
||||
REPLACE_EXISTING
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -60,7 +60,7 @@ public class CacheReproTests {
|
||||
|
||||
|
||||
@Test
|
||||
public void spr11124MultipleAnnotations() throws Exception {
|
||||
public void spr11124MultipleAnnotations() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11124Config.class);
|
||||
Spr11124Service bean = context.getBean(Spr11124Service.class);
|
||||
bean.single(2);
|
||||
@@ -71,7 +71,7 @@ public class CacheReproTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void spr11249PrimitiveVarargs() throws Exception {
|
||||
public void spr11249PrimitiveVarargs() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11249Config.class);
|
||||
Spr11249Service bean = context.getBean(Spr11249Service.class);
|
||||
Object result = bean.doSomething("op", 2, 3);
|
||||
|
||||
Vendored
+2
-2
@@ -44,7 +44,7 @@ public class SimpleKeyGeneratorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleValue(){
|
||||
public void singleValue() {
|
||||
Object k1 = generateKey(new Object[] { "a" });
|
||||
Object k2 = generateKey(new Object[] { "a" });
|
||||
Object k3 = generateKey(new Object[] { "different" });
|
||||
@@ -56,7 +56,7 @@ public class SimpleKeyGeneratorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleValues() {
|
||||
public void multipleValues() {
|
||||
Object k1 = generateKey(new Object[] { "a", 1, "b" });
|
||||
Object k2 = generateKey(new Object[] { "a", 1, "b" });
|
||||
Object k3 = generateKey(new Object[] { "b", 1, "a" });
|
||||
|
||||
+11
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,6 +42,7 @@ import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.componentscan.gh24375.MyComponent;
|
||||
import org.springframework.context.index.CandidateComponentsTestClassLoader;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
@@ -501,6 +502,15 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gh24375() {
|
||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
|
||||
Set<BeanDefinition> components = provider.findCandidateComponents(MyComponent.class.getPackage().getName());
|
||||
assertEquals(1, components.size());
|
||||
assertEquals(MyComponent.class.getName(), components.iterator().next().getBeanClassName());
|
||||
}
|
||||
|
||||
|
||||
private boolean containsBeanClass(Set<BeanDefinition> candidates, Class<?> beanClass) {
|
||||
for (BeanDefinition candidate : candidates) {
|
||||
if (beanClass.getName().equals(candidate.getBeanClassName())) {
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -530,9 +530,10 @@ public class ImportSelectorTests {
|
||||
static Map<String, List<String>> allImports() {
|
||||
return TestImportGroup.imports.entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap((entry) -> entry.getKey().getClassName(),
|
||||
.collect(Collectors.toMap(entry -> entry.getKey().getClassName(),
|
||||
Map.Entry::getValue));
|
||||
}
|
||||
|
||||
private final List<Entry> instanceImports = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.context.annotation.componentscan.gh24375;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface A {
|
||||
|
||||
@AliasFor("value")
|
||||
B other() default @B;
|
||||
|
||||
@AliasFor("other")
|
||||
B value() default @B;
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.context.annotation.componentscan.gh24375;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.ANNOTATION_TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface B {
|
||||
|
||||
String name() default "";
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.context.annotation.componentscan.gh24375;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@A(other = @B)
|
||||
public class MyComponent {
|
||||
}
|
||||
+6
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -794,6 +794,7 @@ public class AnnotationDrivenEventListenerTests {
|
||||
|
||||
@EventListener
|
||||
@Async
|
||||
@Override
|
||||
public void handleAsync(AnotherTestEvent event) {
|
||||
assertTrue(!Thread.currentThread().getName().equals(event.content));
|
||||
this.eventCollector.addEvent(this, event);
|
||||
@@ -820,6 +821,7 @@ public class AnnotationDrivenEventListenerTests {
|
||||
|
||||
@EventListener
|
||||
@Async
|
||||
@Override
|
||||
public void handleAsync(AnotherTestEvent event) {
|
||||
assertTrue(!Thread.currentThread().getName().equals(event.content));
|
||||
this.eventCollector.addEvent(this, event);
|
||||
@@ -902,7 +904,6 @@ public class AnnotationDrivenEventListenerTests {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@EventListener
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ConditionalEvent {
|
||||
@@ -934,18 +935,20 @@ public class AnnotationDrivenEventListenerTests {
|
||||
super.handle(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
@EventListener(condition = "#payload.startsWith('OK')")
|
||||
@Override
|
||||
public void handleString(String payload) {
|
||||
super.handleString(payload);
|
||||
}
|
||||
|
||||
@ConditionalEvent("#root.event.timestamp > #p0")
|
||||
@Override
|
||||
public void handleTimestamp(Long timestamp) {
|
||||
collectEvent(timestamp);
|
||||
}
|
||||
|
||||
@ConditionalEvent("@conditionEvaluator.valid(#p0)")
|
||||
@Override
|
||||
public void handleRatio(Double ratio) {
|
||||
collectEvent(ratio);
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -62,7 +62,6 @@ public class StaticMessageSourceTests extends AbstractApplicationContextTests {
|
||||
@Test
|
||||
@Override
|
||||
public void count() {
|
||||
// These are only checked for current Ctx (not parent ctx)
|
||||
assertCount(15);
|
||||
}
|
||||
|
||||
|
||||
+17
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,7 +46,7 @@ import static org.junit.Assert.*;
|
||||
*/
|
||||
public class DateFormattingTests {
|
||||
|
||||
private final FormattingConversionService conversionService = new FormattingConversionService();
|
||||
private FormattingConversionService conversionService;
|
||||
|
||||
private DataBinder binder;
|
||||
|
||||
@@ -58,6 +58,7 @@ public class DateFormattingTests {
|
||||
}
|
||||
|
||||
private void setup(DateFormatterRegistrar registrar) {
|
||||
conversionService = new FormattingConversionService();
|
||||
DefaultConversionService.addDefaultConverters(conversionService);
|
||||
registrar.registerFormatters(conversionService);
|
||||
|
||||
@@ -148,6 +149,20 @@ public class DateFormattingTests {
|
||||
assertEquals("10/31/09 1:05", binder.getBindingResult().getFieldValue("dateAnnotatedPattern"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindDateAnnotatedPatternWithGlobalFormat() {
|
||||
DateFormatterRegistrar registrar = new DateFormatterRegistrar();
|
||||
DateFormatter dateFormatter = new DateFormatter();
|
||||
dateFormatter.setIso(ISO.DATE_TIME);
|
||||
registrar.setFormatter(dateFormatter);
|
||||
setup(registrar);
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("dateAnnotatedPattern", "10/31/09 1:05");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("10/31/09 1:05", binder.getBindingResult().getFieldValue("dateAnnotatedPattern"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindDateTimeOverflow() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.format.datetime.standard;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.time.Instant;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static java.time.Instant.MAX;
|
||||
import static java.time.Instant.MIN;
|
||||
import static java.time.ZoneId.systemDefault;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link InstantFormatter}.
|
||||
*
|
||||
* @author Andrei Nevedomskii
|
||||
* @author Sam Brannen
|
||||
* @since 5.1.12
|
||||
*/
|
||||
public class InstantFormatterTests {
|
||||
|
||||
private final InstantFormatter instantFormatter = new InstantFormatter();
|
||||
|
||||
|
||||
@Test
|
||||
public void should_parse_an_ISO_formatted_string_representation_of_an_Instant() {
|
||||
new ISOSerializedInstantProvider().provideArguments().forEach(input -> {
|
||||
try {
|
||||
Instant expected = DateTimeFormatter.ISO_INSTANT.parse(input, Instant::from);
|
||||
|
||||
Instant actual = instantFormatter.parse(input, null);
|
||||
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
catch (ParseException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_parse_an_RFC1123_formatted_string_representation_of_an_Instant() {
|
||||
new RFC1123SerializedInstantProvider().provideArguments().forEach(input -> {
|
||||
try {
|
||||
Instant expected = DateTimeFormatter.RFC_1123_DATE_TIME.parse(input, Instant::from);
|
||||
|
||||
Instant actual = instantFormatter.parse(input, null);
|
||||
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
catch (ParseException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_serialize_an_Instant_using_ISO_format_and_ignoring_Locale() {
|
||||
new RandomInstantProvider().randomInstantStream(MIN, MAX).forEach(instant -> {
|
||||
String expected = DateTimeFormatter.ISO_INSTANT.format(instant);
|
||||
|
||||
String actual = instantFormatter.print(instant, null);
|
||||
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private static class RandomInstantProvider {
|
||||
|
||||
private static final long DATA_SET_SIZE = 10;
|
||||
|
||||
private static final Random random = new Random();
|
||||
|
||||
Stream<Instant> randomInstantStream(Instant min, Instant max) {
|
||||
return Stream.concat(Stream.of(Instant.now()), // make sure that the data set includes current instant
|
||||
random.longs(min.getEpochSecond(), max.getEpochSecond()).limit(DATA_SET_SIZE).mapToObj(Instant::ofEpochSecond));
|
||||
}
|
||||
}
|
||||
|
||||
private static class ISOSerializedInstantProvider extends RandomInstantProvider {
|
||||
|
||||
Stream<String> provideArguments() {
|
||||
return randomInstantStream(MIN, MAX).map(DateTimeFormatter.ISO_INSTANT::format);
|
||||
}
|
||||
}
|
||||
|
||||
private static class RFC1123SerializedInstantProvider extends RandomInstantProvider {
|
||||
|
||||
// RFC-1123 supports only 4-digit years
|
||||
private static final Instant min = Instant.parse("0000-01-01T00:00:00.00Z");
|
||||
|
||||
private static final Instant max = Instant.parse("9999-12-31T23:59:59.99Z");
|
||||
|
||||
|
||||
Stream<String> provideArguments() {
|
||||
return randomInstantStream(min, max)
|
||||
.map(DateTimeFormatter.RFC_1123_DATE_TIME.withZone(systemDefault())::format);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -79,11 +79,11 @@ dependencies {
|
||||
optional("io.reactivex.rxjava2:rxjava:${rxjava2Version}")
|
||||
optional("io.netty:netty-buffer")
|
||||
testCompile("io.projectreactor:reactor-test")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
|
||||
testCompile("javax.annotation:javax.annotation-api:1.3.2")
|
||||
testCompile("com.google.code.findbugs:jsr305:3.0.2")
|
||||
testCompile("org.xmlunit:xmlunit-matchers:2.6.2")
|
||||
testCompile("javax.xml.bind:jaxb-api:2.3.1")
|
||||
testCompile("com.fasterxml.woodstox:woodstox-core:5.2.0") {
|
||||
testCompile("com.fasterxml.woodstox:woodstox-core:5.3.0") {
|
||||
exclude group: "stax", module: "stax-api"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +336,15 @@ public class ReflectUtils {
|
||||
public static Constructor getConstructor(Class type, Class[] parameterTypes) {
|
||||
try {
|
||||
Constructor constructor = type.getDeclaredConstructor(parameterTypes);
|
||||
constructor.setAccessible(true);
|
||||
if (System.getSecurityManager() != null) {
|
||||
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||
constructor.setAccessible(true);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
else {
|
||||
constructor.setAccessible(true);
|
||||
}
|
||||
return constructor;
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -169,11 +169,12 @@ public final class GenericTypeResolver {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) genericType;
|
||||
Class<?>[] generics = new Class<?>[parameterizedType.getActualTypeArguments().length];
|
||||
Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
||||
ResolvableType contextType = ResolvableType.forClass(contextClass);
|
||||
for (int i = 0; i < typeArguments.length; i++) {
|
||||
Type typeArgument = typeArguments[i];
|
||||
if (typeArgument instanceof TypeVariable) {
|
||||
ResolvableType resolvedTypeArgument = resolveVariable(
|
||||
(TypeVariable<?>) typeArgument, ResolvableType.forClass(contextClass));
|
||||
(TypeVariable<?>) typeArgument, contextType);
|
||||
if (resolvedTypeArgument != ResolvableType.NONE) {
|
||||
generics[i] = resolvedTypeArgument.resolve();
|
||||
}
|
||||
|
||||
@@ -872,6 +872,12 @@ public class ResolvableType implements Serializable {
|
||||
return forType(ownerType, this.variableResolver).resolveVariable(variable);
|
||||
}
|
||||
}
|
||||
if (this.type instanceof WildcardType) {
|
||||
ResolvableType resolved = resolveType().resolveVariable(variable);
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
if (this.variableResolver != null) {
|
||||
return this.variableResolver.resolveVariable(variable);
|
||||
}
|
||||
@@ -982,7 +988,7 @@ public class ResolvableType implements Serializable {
|
||||
* using the full generic type information for assignability checks.
|
||||
* For example: {@code ResolvableType.forClass(MyArrayList.class)}.
|
||||
* @param clazz the class to introspect ({@code null} is semantically
|
||||
* equivalent to {@code Object.class} for typical use cases here}
|
||||
* equivalent to {@code Object.class} for typical use cases here)
|
||||
* @return a {@link ResolvableType} for the specified class
|
||||
* @see #forClass(Class, Class)
|
||||
* @see #forClassWithGenerics(Class, Class...)
|
||||
@@ -997,7 +1003,7 @@ public class ResolvableType implements Serializable {
|
||||
* {@link Class#isAssignableFrom}, which this serves as a wrapper for.
|
||||
* For example: {@code ResolvableType.forRawClass(List.class)}.
|
||||
* @param clazz the class to introspect ({@code null} is semantically
|
||||
* equivalent to {@code Object.class} for typical use cases here}
|
||||
* equivalent to {@code Object.class} for typical use cases here)
|
||||
* @return a {@link ResolvableType} for the specified class
|
||||
* @since 4.2
|
||||
* @see #forClass(Class)
|
||||
@@ -1485,10 +1491,10 @@ public class ResolvableType implements Serializable {
|
||||
@Override
|
||||
@Nullable
|
||||
public ResolvableType resolveVariable(TypeVariable<?> variable) {
|
||||
TypeVariable<?> variableToCompare = SerializableTypeWrapper.unwrap(variable);
|
||||
for (int i = 0; i < this.variables.length; i++) {
|
||||
TypeVariable<?> v1 = SerializableTypeWrapper.unwrap(this.variables[i]);
|
||||
TypeVariable<?> v2 = SerializableTypeWrapper.unwrap(variable);
|
||||
if (ObjectUtils.nullSafeEquals(v1, v2)) {
|
||||
TypeVariable<?> resolvedVariable = SerializableTypeWrapper.unwrap(this.variables[i]);
|
||||
if (ObjectUtils.nullSafeEquals(resolvedVariable, variableToCompare)) {
|
||||
return this.generics[i];
|
||||
}
|
||||
}
|
||||
|
||||
+29
-1
@@ -47,12 +47,40 @@ import org.springframework.util.MimeType;
|
||||
*/
|
||||
public abstract class AbstractDataBufferDecoder<T> extends AbstractDecoder<T> {
|
||||
|
||||
private int maxInMemorySize = -1;
|
||||
|
||||
|
||||
protected AbstractDataBufferDecoder(MimeType... supportedMimeTypes) {
|
||||
super(supportedMimeTypes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configure a limit on the number of bytes that can be buffered whenever
|
||||
* the input stream needs to be aggregated. This can be a result of
|
||||
* decoding to a single {@code DataBuffer},
|
||||
* {@link java.nio.ByteBuffer ByteBuffer}, {@code byte[]},
|
||||
* {@link org.springframework.core.io.Resource Resource}, {@code String}, etc.
|
||||
* It can also occur when splitting the input stream, e.g. delimited text,
|
||||
* in which case the limit applies to data buffered between delimiters.
|
||||
* <p>By default in 5.1 this is set to -1, unlimited. In 5.2 the default
|
||||
* value for this limit is set to 256K.
|
||||
* @param byteCount the max number of bytes to buffer, or -1 for unlimited
|
||||
* @since 5.1.11
|
||||
*/
|
||||
public void setMaxInMemorySize(int byteCount) {
|
||||
this.maxInMemorySize = byteCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link #setMaxInMemorySize configured} byte count limit.
|
||||
* @since 5.1.11
|
||||
*/
|
||||
public int getMaxInMemorySize() {
|
||||
return this.maxInMemorySize;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Flux<T> decode(Publisher<DataBuffer> input, ResolvableType elementType,
|
||||
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
|
||||
@@ -64,7 +92,7 @@ public abstract class AbstractDataBufferDecoder<T> extends AbstractDecoder<T> {
|
||||
public Mono<T> decodeToMono(Publisher<DataBuffer> input, ResolvableType elementType,
|
||||
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
|
||||
|
||||
return DataBufferUtils.join(input)
|
||||
return DataBufferUtils.join(input, this.maxInMemorySize)
|
||||
.map(buffer -> decodeDataBuffer(buffer, elementType, mimeType, hints));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,14 +25,17 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferLimitException;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
||||
import org.springframework.core.io.buffer.LimitedDataBufferList;
|
||||
import org.springframework.core.io.buffer.PooledDataBuffer;
|
||||
import org.springframework.core.log.LogFormatUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -92,11 +95,44 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
|
||||
|
||||
List<byte[]> delimiterBytes = getDelimiterBytes(mimeType);
|
||||
|
||||
Flux<DataBuffer> inputFlux = Flux.from(input)
|
||||
.flatMapIterable(buffer -> splitOnDelimiter(buffer, delimiterBytes))
|
||||
.bufferUntil(buffer -> buffer == END_FRAME)
|
||||
.map(StringDecoder::joinUntilEndFrame)
|
||||
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
|
||||
Flux<DataBuffer> inputFlux = Flux.defer(() -> {
|
||||
if (getMaxInMemorySize() != -1) {
|
||||
|
||||
// Passing limiter into endFrameAfterDelimiter helps to ensure that in case of one DataBuffer
|
||||
// containing multiple lines, the limit is checked and raised immediately without accumulating
|
||||
// subsequent lines. This is necessary because concatMapIterable doesn't respect doOnDiscard.
|
||||
// When reactor-core#1925 is resolved, we could replace bufferUntil with:
|
||||
|
||||
// .windowUntil(buffer -> buffer instanceof EndFrameBuffer)
|
||||
// .concatMap(fluxes -> fluxes.collect(() -> new LimitedDataBufferList(getMaxInMemorySize()), LimitedDataBufferList::add))
|
||||
|
||||
LimitedDataBufferList limiter = new LimitedDataBufferList(getMaxInMemorySize());
|
||||
|
||||
return Flux.from(input)
|
||||
.concatMapIterable(buffer -> splitOnDelimiter(buffer, delimiterBytes, limiter))
|
||||
.bufferUntil(buffer -> buffer == END_FRAME)
|
||||
.map(StringDecoder::joinUntilEndFrame)
|
||||
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
|
||||
}
|
||||
else {
|
||||
|
||||
// When the decoder is unlimited (-1), concatMapIterable will cache buffers that may not
|
||||
// be released if cancel is signalled before they are turned into String lines
|
||||
// (see test maxInMemoryLimitReleasesUnprocessedLinesWhenUnlimited).
|
||||
// When reactor-core#1925 is resolved, the workaround can be removed and the entire
|
||||
// else clause possibly dropped.
|
||||
|
||||
ConcatMapIterableDiscardWorkaroundCache cache = new ConcatMapIterableDiscardWorkaroundCache();
|
||||
|
||||
return Flux.from(input)
|
||||
.concatMapIterable(buffer -> cache.addAll(splitOnDelimiter(buffer, delimiterBytes, null)))
|
||||
.doOnNext(cache)
|
||||
.doOnCancel(cache)
|
||||
.bufferUntil(buffer -> buffer == END_FRAME)
|
||||
.map(StringDecoder::joinUntilEndFrame)
|
||||
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
|
||||
}
|
||||
});
|
||||
|
||||
return super.decode(inputFlux, elementType, mimeType, hints);
|
||||
}
|
||||
@@ -116,7 +152,9 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
|
||||
* Split the given data buffer on delimiter boundaries.
|
||||
* The returned Flux contains an {@link #END_FRAME} buffer after each delimiter.
|
||||
*/
|
||||
private List<DataBuffer> splitOnDelimiter(DataBuffer buffer, List<byte[]> delimiterBytes) {
|
||||
private List<DataBuffer> splitOnDelimiter(
|
||||
DataBuffer buffer, List<byte[]> delimiterBytes, @Nullable LimitedDataBufferList limiter) {
|
||||
|
||||
List<DataBuffer> frames = new ArrayList<>();
|
||||
try {
|
||||
do {
|
||||
@@ -138,15 +176,28 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
|
||||
buffer.readPosition(readPosition + length + matchingDelimiter.length);
|
||||
frames.add(DataBufferUtils.retain(frame));
|
||||
frames.add(END_FRAME);
|
||||
if (limiter != null) {
|
||||
limiter.add(frame); // enforce the limit
|
||||
limiter.clear();
|
||||
}
|
||||
}
|
||||
else {
|
||||
frame = buffer.slice(readPosition, buffer.readableByteCount());
|
||||
buffer.readPosition(readPosition + buffer.readableByteCount());
|
||||
frames.add(DataBufferUtils.retain(frame));
|
||||
if (limiter != null) {
|
||||
limiter.add(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (buffer.readableByteCount() > 0);
|
||||
}
|
||||
catch (DataBufferLimitException ex) {
|
||||
if (limiter != null) {
|
||||
limiter.releaseAndClear();
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
for (DataBuffer frame : frames) {
|
||||
DataBufferUtils.release(frame);
|
||||
@@ -283,4 +334,33 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
|
||||
new MimeType("text", "plain", DEFAULT_CHARSET), MimeTypeUtils.ALL);
|
||||
}
|
||||
|
||||
|
||||
private class ConcatMapIterableDiscardWorkaroundCache implements Consumer<DataBuffer>, Runnable {
|
||||
|
||||
private final List<DataBuffer> buffers = new ArrayList<>();
|
||||
|
||||
|
||||
public List<DataBuffer> addAll(List<DataBuffer> buffersToAdd) {
|
||||
this.buffers.addAll(buffersToAdd);
|
||||
return buffersToAdd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DataBuffer dataBuffer) {
|
||||
this.buffers.remove(dataBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.buffers.forEach(buffer -> {
|
||||
try {
|
||||
DataBufferUtils.release(buffer);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Keep going..
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,8 @@ import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Context about a type to convert from or to.
|
||||
* Contextual descriptor about a type to convert from or to.
|
||||
* Capable of representing arrays and generic collection types.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Andy Clement
|
||||
@@ -45,6 +46,8 @@ import org.springframework.util.ObjectUtils;
|
||||
* @author Sam Brannen
|
||||
* @author Stephane Nicoll
|
||||
* @since 3.0
|
||||
* @see ConversionService#canConvert(TypeDescriptor, TypeDescriptor)
|
||||
* @see ConversionService#convert(Object, TypeDescriptor, TypeDescriptor)
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class TypeDescriptor implements Serializable {
|
||||
@@ -322,9 +325,9 @@ public class TypeDescriptor implements Serializable {
|
||||
* If this type is a {@code Stream}, returns the stream's component type.
|
||||
* If this type is a {@link Collection} and it is parameterized, returns the Collection's element type.
|
||||
* If the Collection is not parameterized, returns {@code null} indicating the element type is not declared.
|
||||
* @return the array component type or Collection element type, or {@code null} if this type is a
|
||||
* Collection but its element type is not parameterized
|
||||
* @throws IllegalStateException if this type is not a {@code java.util.Collection} or array type
|
||||
* @return the array component type or Collection element type, or {@code null} if this type is not
|
||||
* an array type or a {@code java.util.Collection} or if its element type is not parameterized
|
||||
* @see #elementTypeDescriptor(Object)
|
||||
*/
|
||||
@Nullable
|
||||
public TypeDescriptor getElementTypeDescriptor() {
|
||||
@@ -351,8 +354,7 @@ public class TypeDescriptor implements Serializable {
|
||||
* TypeDescriptor that is returned.
|
||||
* @param element the collection or array element
|
||||
* @return a element type descriptor, narrowed to the type of the provided element
|
||||
* @throws IllegalStateException if this type is not a {@code java.util.Collection}
|
||||
* or array type
|
||||
* @see #getElementTypeDescriptor()
|
||||
* @see #narrow(Object)
|
||||
*/
|
||||
@Nullable
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -49,6 +49,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 28.12.2003
|
||||
* @see #FileSystemResource(String)
|
||||
* @see #FileSystemResource(File)
|
||||
* @see #FileSystemResource(Path)
|
||||
* @see java.io.File
|
||||
@@ -108,6 +109,15 @@ public class FileSystemResource extends AbstractResource implements WritableReso
|
||||
* <p>In contrast to {@link PathResource}, this variant strictly follows the
|
||||
* general {@link FileSystemResource} conventions, in particular in terms of
|
||||
* path cleaning and {@link #createRelative(String)} handling.
|
||||
* <p>Note: When building relative resources via {@link #createRelative},
|
||||
* the relative path will apply <i>at the same directory level</i>:
|
||||
* e.g. Paths.get("C:/dir1"), relative path "dir2" -> "C:/dir2"!
|
||||
* If you prefer to have relative paths built underneath the given root directory,
|
||||
* use the {@link #FileSystemResource(String) constructor with a file path}
|
||||
* to append a trailing slash to the root path: "C:/dir1/", which indicates
|
||||
* this directory as root for all relative paths. Alternatively, consider
|
||||
* using {@link PathResource#PathResource(Path)} for {@code java.nio.path.Path}
|
||||
* resolution in {@code createRelative}, always nesting relative paths.
|
||||
* @param filePath a Path handle to a file
|
||||
* @since 5.1
|
||||
* @see #FileSystemResource(File)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,15 +44,16 @@ import org.springframework.util.Assert;
|
||||
* in {@link FileSystemResource#FileSystemResource(Path) FileSystemResource},
|
||||
* applying Spring's standard String-based path transformations but
|
||||
* performing all operations via the {@link java.nio.file.Files} API.
|
||||
* This {@code PathResource} is effectively a pure {@code java.nio.path.Path}
|
||||
* based alternative with different {@code createRelative} behavior.
|
||||
*
|
||||
* @author Philippe Marschall
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
* @see java.nio.file.Path
|
||||
* @see java.nio.file.Files
|
||||
* @deprecated as of 5.1.1, in favor of {@link FileSystemResource#FileSystemResource(Path)}
|
||||
* @see FileSystemResource
|
||||
*/
|
||||
@Deprecated
|
||||
public class PathResource extends AbstractResource implements WritableResource {
|
||||
|
||||
private final Path path;
|
||||
@@ -252,7 +253,7 @@ public class PathResource extends AbstractResource implements WritableResource {
|
||||
* @see java.nio.file.Path#resolve(String)
|
||||
*/
|
||||
@Override
|
||||
public Resource createRelative(String relativePath) throws IOException {
|
||||
public Resource createRelative(String relativePath) {
|
||||
return new PathResource(this.path.resolve(relativePath));
|
||||
}
|
||||
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.core.io.buffer;
|
||||
|
||||
/**
|
||||
* Exception that indicates the cumulative number of bytes consumed from a
|
||||
* stream of {@link DataBuffer DataBuffer}'s exceeded some pre-configured limit.
|
||||
* This can be raised when data buffers are cached and aggregated, e.g.
|
||||
* {@link DataBufferUtils#join}. Or it could also be raised when data buffers
|
||||
* have been released but a parsed representation is being aggregated, e.g. async
|
||||
* parsing with Jackson.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.1.11
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class DataBufferLimitException extends IllegalStateException {
|
||||
|
||||
|
||||
public DataBufferLimitException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -437,14 +437,36 @@ public abstract class DataBufferUtils {
|
||||
* @since 5.0.3
|
||||
*/
|
||||
public static Mono<DataBuffer> join(Publisher<DataBuffer> dataBuffers) {
|
||||
Assert.notNull(dataBuffers, "'dataBuffers' must not be null");
|
||||
return join(dataBuffers, -1);
|
||||
}
|
||||
|
||||
return Flux.from(dataBuffers)
|
||||
.collectList()
|
||||
/**
|
||||
* Variant of {@link #join(Publisher)} that behaves the same way up until
|
||||
* the specified max number of bytes to buffer. Once the limit is exceeded,
|
||||
* {@link DataBufferLimitException} is raised.
|
||||
* @param buffers the data buffers that are to be composed
|
||||
* @param maxByteCount the max number of bytes to buffer, or -1 for unlimited
|
||||
* @return a buffer with the aggregated content, possibly an empty Mono if
|
||||
* the max number of bytes to buffer is exceeded.
|
||||
* @throws DataBufferLimitException if maxByteCount is exceeded
|
||||
* @since 5.1.11
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Mono<DataBuffer> join(Publisher<? extends DataBuffer> buffers, int maxByteCount) {
|
||||
Assert.notNull(buffers, "'dataBuffers' must not be null");
|
||||
|
||||
if (buffers instanceof Mono) {
|
||||
return (Mono<DataBuffer>) buffers;
|
||||
}
|
||||
|
||||
// TODO: Drop doOnDiscard(LimitedDataBufferList.class, ...) (reactor-core#1924)
|
||||
|
||||
return Flux.from(buffers)
|
||||
.collect(() -> new LimitedDataBufferList(maxByteCount), LimitedDataBufferList::add)
|
||||
.filter(list -> !list.isEmpty())
|
||||
.map(list -> list.get(0).factory().join(list))
|
||||
.doOnDiscard(LimitedDataBufferList.class, LimitedDataBufferList::releaseAndClear)
|
||||
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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.core.io.buffer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
/**
|
||||
* Custom {@link List} to collect data buffers with and enforce a
|
||||
* limit on the total number of bytes buffered. For use with "collect" or
|
||||
* other buffering operators in declarative APIs, e.g. {@link Flux}.
|
||||
*
|
||||
* <p>Adding elements increases the byte count and if the limit is exceeded,
|
||||
* {@link DataBufferLimitException} is raised. {@link #clear()} resets the
|
||||
* count. Remove and set are not supported.
|
||||
*
|
||||
* <p><strong>Note:</strong> This class does not automatically release the
|
||||
* buffers it contains. It is usually preferable to use hooks such as
|
||||
* {@link Flux#doOnDiscard} that also take care of cancel and error signals,
|
||||
* or otherwise {@link #releaseAndClear()} can be used.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.1.11
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class LimitedDataBufferList extends ArrayList<DataBuffer> {
|
||||
|
||||
private final int maxByteCount;
|
||||
|
||||
private int byteCount;
|
||||
|
||||
|
||||
public LimitedDataBufferList(int maxByteCount) {
|
||||
this.maxByteCount = maxByteCount;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean add(DataBuffer buffer) {
|
||||
boolean result = super.add(buffer);
|
||||
if (result) {
|
||||
updateCount(buffer.readableByteCount());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, DataBuffer buffer) {
|
||||
super.add(index, buffer);
|
||||
updateCount(buffer.readableByteCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends DataBuffer> collection) {
|
||||
boolean result = super.addAll(collection);
|
||||
collection.forEach(buffer -> updateCount(buffer.readableByteCount()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends DataBuffer> collection) {
|
||||
boolean result = super.addAll(index, collection);
|
||||
collection.forEach(buffer -> updateCount(buffer.readableByteCount()));
|
||||
return result;
|
||||
}
|
||||
|
||||
private void updateCount(int bytesToAdd) {
|
||||
if (this.maxByteCount < 0) {
|
||||
return;
|
||||
}
|
||||
if (bytesToAdd > Integer.MAX_VALUE - this.byteCount) {
|
||||
raiseLimitException();
|
||||
}
|
||||
else {
|
||||
this.byteCount += bytesToAdd;
|
||||
if (this.byteCount > this.maxByteCount) {
|
||||
raiseLimitException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void raiseLimitException() {
|
||||
// Do not release here, it's likely down via doOnDiscard..
|
||||
throw new DataBufferLimitException(
|
||||
"Exceeded limit on max bytes to buffer : " + this.maxByteCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataBuffer remove(int index) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeRange(int fromIndex, int toIndex) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeIf(Predicate<? super DataBuffer> filter) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataBuffer set(int index, DataBuffer element) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.byteCount = 0;
|
||||
super.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to {@link DataBufferUtils#release release} all data buffers and
|
||||
* then {@link #clear()}.
|
||||
*/
|
||||
public void releaseAndClear() {
|
||||
forEach(buf -> {
|
||||
try {
|
||||
DataBufferUtils.release(buf);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Keep going..
|
||||
}
|
||||
});
|
||||
clear();
|
||||
}
|
||||
|
||||
}
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -149,9 +149,10 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho
|
||||
MultiValueMap<String, Object> allAttributes = new LinkedMultiValueMap<>();
|
||||
List<AnnotationAttributes> attributesList = this.attributesMap.get(annotationName);
|
||||
if (attributesList != null) {
|
||||
String annotatedElement = "method '" + getMethodName() + '\'';
|
||||
for (AnnotationAttributes annotationAttributes : attributesList) {
|
||||
AnnotationAttributes convertedAttributes = AnnotationReadingVisitorUtils.convertClassValues(
|
||||
"method '" + getMethodName() + "'", this.classLoader, annotationAttributes, classValuesAsString);
|
||||
annotatedElement, this.classLoader, annotationAttributes, classValuesAsString);
|
||||
convertedAttributes.forEach(allAttributes::add);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +110,11 @@ public abstract class ClassUtils {
|
||||
*/
|
||||
private static final Set<Class<?>> javaLanguageInterfaces;
|
||||
|
||||
/**
|
||||
* Cache for equivalent methods on an interface implemented by the declaring class.
|
||||
*/
|
||||
private static final Map<Method, Method> interfaceMethodCache = new ConcurrentReferenceHashMap<>(256);
|
||||
|
||||
|
||||
static {
|
||||
primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
|
||||
@@ -1291,13 +1296,16 @@ public abstract class ClassUtils {
|
||||
* @see #getMostSpecificMethod
|
||||
*/
|
||||
public static Method getInterfaceMethodIfPossible(Method method) {
|
||||
if (Modifier.isPublic(method.getModifiers()) && !method.getDeclaringClass().isInterface()) {
|
||||
Class<?> current = method.getDeclaringClass();
|
||||
if (!Modifier.isPublic(method.getModifiers()) || method.getDeclaringClass().isInterface()) {
|
||||
return method;
|
||||
}
|
||||
return interfaceMethodCache.computeIfAbsent(method, key -> {
|
||||
Class<?> current = key.getDeclaringClass();
|
||||
while (current != null && current != Object.class) {
|
||||
Class<?>[] ifcs = current.getInterfaces();
|
||||
for (Class<?> ifc : ifcs) {
|
||||
try {
|
||||
return ifc.getMethod(method.getName(), method.getParameterTypes());
|
||||
return ifc.getMethod(key.getName(), key.getParameterTypes());
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
// ignore
|
||||
@@ -1305,8 +1313,8 @@ public abstract class ClassUtils {
|
||||
}
|
||||
current = current.getSuperclass();
|
||||
}
|
||||
}
|
||||
return method;
|
||||
return key;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -417,14 +417,14 @@ public abstract class StringUtils {
|
||||
int pos = 0; // our position in the old string
|
||||
int patLen = oldPattern.length();
|
||||
while (index >= 0) {
|
||||
sb.append(inString.substring(pos, index));
|
||||
sb.append(inString, pos, index);
|
||||
sb.append(newPattern);
|
||||
pos = index + patLen;
|
||||
index = inString.indexOf(oldPattern, pos);
|
||||
}
|
||||
|
||||
// append any characters to the right of a match
|
||||
sb.append(inString.substring(pos));
|
||||
sb.append(inString, pos, inString.length());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,38 +16,53 @@
|
||||
|
||||
package org.springframework.util.unit;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A standard set of data size units.
|
||||
* A standard set of {@link DataSize} units.
|
||||
*
|
||||
* <p>The unit prefixes used in this class are
|
||||
* <a href="https://en.wikipedia.org/wiki/Binary_prefix">binary prefixes</a>
|
||||
* indicating multiplication by powers of 2. The following table displays the
|
||||
* enum constants defined in this class and corresponding values.
|
||||
*
|
||||
* <p>
|
||||
* <table border="1">
|
||||
* <tr><th>Constant</th><th>Data Size</th><th>Power of 2</th><th>Size in Bytes</th></tr>
|
||||
* <tr><td>{@link #BYTES}</td><td>1B</td><td>2^0</td><td>1</td></tr>
|
||||
* <tr><td>{@link #KILOBYTES}</td><td>1KB</td><td>2^10</td><td>1,024</td></tr>
|
||||
* <tr><td>{@link #MEGABYTES}</td><td>1MB</td><td>2^20</td><td>1,048,576</td></tr>
|
||||
* <tr><td>{@link #GIGABYTES}</td><td>1GB</td><td>2^30</td><td>1,073,741,824</td></tr>
|
||||
* <tr><td>{@link #TERABYTES}</td><td>1TB</td><td>2^40</td><td>1,099,511,627,776</td></tr>
|
||||
* </table>
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Sam Brannen
|
||||
* @since 5.1
|
||||
* @see DataSize
|
||||
*/
|
||||
public enum DataUnit {
|
||||
|
||||
/**
|
||||
* Bytes.
|
||||
* Bytes, represented by suffix {@code B}.
|
||||
*/
|
||||
BYTES("B", DataSize.ofBytes(1)),
|
||||
|
||||
/**
|
||||
* Kilobytes.
|
||||
* Kilobytes, represented by suffix {@code KB}.
|
||||
*/
|
||||
KILOBYTES("KB", DataSize.ofKilobytes(1)),
|
||||
|
||||
/**
|
||||
* Megabytes.
|
||||
* Megabytes, represented by suffix {@code MB}.
|
||||
*/
|
||||
MEGABYTES("MB", DataSize.ofMegabytes(1)),
|
||||
|
||||
/**
|
||||
* Gigabytes.
|
||||
* Gigabytes, represented by suffix {@code GB}.
|
||||
*/
|
||||
GIGABYTES("GB", DataSize.ofGigabytes(1)),
|
||||
|
||||
/**
|
||||
* Terabytes.
|
||||
* Terabytes, represented by suffix {@code TB}.
|
||||
*/
|
||||
TERABYTES("TB", DataSize.ofTerabytes(1));
|
||||
|
||||
@@ -68,18 +83,18 @@ public enum DataUnit {
|
||||
|
||||
/**
|
||||
* Return the {@link DataUnit} matching the specified {@code suffix}.
|
||||
* @param suffix one of the standard suffix
|
||||
* @param suffix one of the standard suffixes
|
||||
* @return the {@link DataUnit} matching the specified {@code suffix}
|
||||
* @throws IllegalArgumentException if the suffix does not match any
|
||||
* of this enum's constants
|
||||
* @throws IllegalArgumentException if the suffix does not match the suffix
|
||||
* of any of this enum's constants
|
||||
*/
|
||||
public static DataUnit fromSuffix(String suffix) {
|
||||
for (DataUnit candidate : values()) {
|
||||
if (Objects.equals(candidate.suffix, suffix)) {
|
||||
if (candidate.suffix.equals(suffix)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown unit '" + suffix + "'");
|
||||
throw new IllegalArgumentException("Unknown data unit suffix '" + suffix + "'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -684,10 +684,16 @@ public class ResolvableTypeTests {
|
||||
|
||||
@Test
|
||||
public void resolveBoundedTypeVariableResult() throws Exception {
|
||||
ResolvableType type = ResolvableType.forMethodReturnType(Methods.class.getMethod("boundedTypeVaraibleResult"));
|
||||
ResolvableType type = ResolvableType.forMethodReturnType(Methods.class.getMethod("boundedTypeVariableResult"));
|
||||
assertThat(type.resolve(), equalTo((Class) CharSequence.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveBoundedTypeVariableWildcardResult() throws Exception {
|
||||
ResolvableType type = ResolvableType.forMethodReturnType(Methods.class.getMethod("boundedTypeVariableWildcardResult"));
|
||||
assertThat(type.getGeneric(1).asCollection().resolveGeneric(), equalTo((Class) CharSequence.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveVariableNotFound() throws Exception {
|
||||
ResolvableType type = ResolvableType.forMethodReturnType(Methods.class.getMethod("typedReturn"));
|
||||
@@ -695,27 +701,14 @@ public class ResolvableTypeTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTypeVaraibleFromMethodReturn() throws Exception {
|
||||
ResolvableType type = ResolvableType.forMethodReturnType(Methods.class.getMethod("typedReturn"));
|
||||
assertThat(type.resolve(), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTypeVaraibleFromMethodReturnWithInstanceClass() throws Exception {
|
||||
ResolvableType type = ResolvableType.forMethodReturnType(
|
||||
Methods.class.getMethod("typedReturn"), TypedMethods.class);
|
||||
assertThat(type.resolve(), equalTo((Class) String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTypeVaraibleFromSimpleInterfaceType() {
|
||||
public void resolveTypeVariableFromSimpleInterfaceType() {
|
||||
ResolvableType type = ResolvableType.forClass(
|
||||
MySimpleInterfaceType.class).as(MyInterfaceType.class);
|
||||
assertThat(type.resolveGeneric(), equalTo((Class) String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTypeVaraibleFromSimpleCollectionInterfaceType() {
|
||||
public void resolveTypeVariableFromSimpleCollectionInterfaceType() {
|
||||
ResolvableType type = ResolvableType.forClass(
|
||||
MyCollectionInterfaceType.class).as(MyInterfaceType.class);
|
||||
assertThat(type.resolveGeneric(), equalTo((Class) Collection.class));
|
||||
@@ -723,14 +716,14 @@ public class ResolvableTypeTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTypeVaraibleFromSimpleSuperclassType() {
|
||||
public void resolveTypeVariableFromSimpleSuperclassType() {
|
||||
ResolvableType type = ResolvableType.forClass(
|
||||
MySimpleSuperclassType.class).as(MySuperclassType.class);
|
||||
assertThat(type.resolveGeneric(), equalTo((Class) String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTypeVaraibleFromSimpleCollectionSuperclassType() {
|
||||
public void resolveTypeVariableFromSimpleCollectionSuperclassType() {
|
||||
ResolvableType type = ResolvableType.forClass(
|
||||
MyCollectionSuperclassType.class).as(MySuperclassType.class);
|
||||
assertThat(type.resolveGeneric(), equalTo((Class) Collection.class));
|
||||
@@ -1459,7 +1452,9 @@ public class ResolvableTypeTests {
|
||||
|
||||
void charSequenceParameter(List<CharSequence> cs);
|
||||
|
||||
<R extends CharSequence & Serializable> R boundedTypeVaraibleResult();
|
||||
<R extends CharSequence & Serializable> R boundedTypeVariableResult();
|
||||
|
||||
Map<String, ? extends List<? extends CharSequence>> boundedTypeVariableWildcardResult();
|
||||
|
||||
void nested(Map<Map<String, Integer>, Map<Byte, Long>> p);
|
||||
|
||||
|
||||
+39
-1
@@ -488,6 +488,20 @@ public class AnnotatedElementUtilsTests {
|
||||
assertTrue(isAnnotated(element, name));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMergedAnnotationWithImplicitAliasesWithDefaultsInMetaAnnotationOnComposedAnnotation() {
|
||||
Class<?> element = ImplicitAliasesWithDefaultsClass.class;
|
||||
String name = AliasesWithDefaults.class.getName();
|
||||
AliasesWithDefaults annotation = getMergedAnnotation(element, AliasesWithDefaults.class);
|
||||
|
||||
assertNotNull("Should find @AliasesWithDefaults on " + element.getSimpleName(), annotation);
|
||||
assertEquals("a1", "ImplicitAliasesWithDefaults", annotation.a1());
|
||||
assertEquals("a2", "ImplicitAliasesWithDefaults", annotation.a2());
|
||||
|
||||
// Verify contracts between utility methods:
|
||||
assertTrue(isAnnotated(element, name));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMergedAnnotationAttributesWithInvalidConventionBasedComposedAnnotation() {
|
||||
Class<?> element = InvalidConventionBasedComposedContextConfigClass.class;
|
||||
@@ -958,7 +972,6 @@ public class AnnotatedElementUtilsTests {
|
||||
String[] xmlConfigFiles() default {};
|
||||
}
|
||||
|
||||
|
||||
@ContextConfig
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface AliasedComposedContextConfig {
|
||||
@@ -999,6 +1012,27 @@ public class AnnotatedElementUtilsTests {
|
||||
@interface ComposedImplicitAliasesContextConfig {
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface AliasesWithDefaults {
|
||||
|
||||
@AliasFor("a2")
|
||||
String a1() default "AliasesWithDefaults";
|
||||
|
||||
@AliasFor("a1")
|
||||
String a2() default "AliasesWithDefaults";
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@AliasesWithDefaults
|
||||
@interface ImplicitAliasesWithDefaults {
|
||||
|
||||
@AliasFor(annotation = AliasesWithDefaults.class, attribute = "a1")
|
||||
String b1() default "ImplicitAliasesWithDefaults";
|
||||
|
||||
@AliasFor(annotation = AliasesWithDefaults.class, attribute = "a2")
|
||||
String b2() default "ImplicitAliasesWithDefaults";
|
||||
}
|
||||
|
||||
@ImplicitAliasesContextConfig
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface TransitiveImplicitAliasesContextConfig {
|
||||
@@ -1296,6 +1330,10 @@ public class AnnotatedElementUtilsTests {
|
||||
static class ImplicitAliasesContextConfigClass3 {
|
||||
}
|
||||
|
||||
@ImplicitAliasesWithDefaults
|
||||
static class ImplicitAliasesWithDefaultsClass {
|
||||
}
|
||||
|
||||
@TransitiveImplicitAliasesContextConfig(groovy = "test.groovy")
|
||||
static class TransitiveImplicitAliasesContextConfigClass {
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,6 +29,7 @@ import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferLimitException;
|
||||
import org.springframework.util.MimeType;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
|
||||
@@ -126,6 +127,33 @@ public class StringDecoderTests extends AbstractDecoderTestCase<StringDecoder> {
|
||||
.verify());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void maxInMemoryLimit() {
|
||||
Flux<DataBuffer> input = Flux.just(
|
||||
stringBuffer("abc\n"), stringBuffer("defg\n"), stringBuffer("hijkl\n"));
|
||||
|
||||
this.decoder.setMaxInMemorySize(4);
|
||||
testDecode(input, String.class, step ->
|
||||
step.expectNext("abc", "defg").verifyError(DataBufferLimitException.class));
|
||||
}
|
||||
|
||||
@Test // gh-24312
|
||||
public void maxInMemoryLimitReleaseUnprocessedLinesFromCurrentBuffer() {
|
||||
Flux<DataBuffer> input = Flux.just(
|
||||
stringBuffer("TOO MUCH DATA\nanother line\n\nand another\n"));
|
||||
|
||||
this.decoder.setMaxInMemorySize(5);
|
||||
testDecode(input, String.class, step -> step.verifyError(DataBufferLimitException.class));
|
||||
}
|
||||
|
||||
@Test // gh-24339
|
||||
public void maxInMemoryLimitReleaseUnprocessedLinesWhenUnlimited() {
|
||||
Flux<DataBuffer> input = Flux.just(stringBuffer("Line 1\nLine 2\nLine 3\n"));
|
||||
|
||||
this.decoder.setMaxInMemorySize(-1);
|
||||
testDecodeCancel(input, ResolvableType.forClass(String.class), null, Collections.emptyMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decodeNewLineIncludeDelimiters() {
|
||||
this.decoder = StringDecoder.allMimeTypes(StringDecoder.DEFAULT_DELIMITERS, false);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.core.io;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -129,6 +130,14 @@ public class ResourceTests {
|
||||
assertEquals(new FileSystemResource(file), resource);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileSystemResourceWithFile() throws IOException {
|
||||
File file = new File(getClass().getResource("Resource.class").getFile());
|
||||
Resource resource = new FileSystemResource(file);
|
||||
doTestResource(resource);
|
||||
assertEquals(new FileSystemResource(file), resource);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileSystemResourceWithFilePath() throws Exception {
|
||||
Path filePath = Paths.get(getClass().getResource("Resource.class").toURI());
|
||||
|
||||
+21
-7
@@ -48,11 +48,14 @@ import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.buffer.support.DataBufferTestUtils;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.anyLong;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.isA;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
@@ -716,14 +719,25 @@ public class DataBufferUtilsTests extends AbstractDataBufferAllocatingTestCase {
|
||||
Mono<DataBuffer> result = DataBufferUtils.join(flux);
|
||||
|
||||
StepVerifier.create(result)
|
||||
.consumeNextWith(dataBuffer -> {
|
||||
assertEquals("foobarbaz",
|
||||
DataBufferTestUtils.dumpString(dataBuffer, StandardCharsets.UTF_8));
|
||||
release(dataBuffer);
|
||||
.consumeNextWith(buf -> {
|
||||
assertEquals("foobarbaz", DataBufferTestUtils.dumpString(buf, StandardCharsets.UTF_8));
|
||||
release(buf);
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void joinWithLimit() {
|
||||
DataBuffer foo = stringBuffer("foo");
|
||||
DataBuffer bar = stringBuffer("bar");
|
||||
DataBuffer baz = stringBuffer("baz");
|
||||
Flux<DataBuffer> flux = Flux.just(foo, bar, baz);
|
||||
Mono<DataBuffer> result = DataBufferUtils.join(flux, 8);
|
||||
|
||||
StepVerifier.create(result)
|
||||
.verifyError(DataBufferLimitException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void joinErrors() {
|
||||
DataBuffer foo = stringBuffer("foo");
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.core.io.buffer;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link LimitedDataBufferList}.
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.1.11
|
||||
*/
|
||||
public class LimitedDataBufferListTests {
|
||||
|
||||
private final static DataBufferFactory bufferFactory = new DefaultDataBufferFactory();
|
||||
|
||||
|
||||
@Test
|
||||
public void limitEnforced() {
|
||||
try {
|
||||
new LimitedDataBufferList(5).add(toDataBuffer("123456"));
|
||||
fail();
|
||||
}
|
||||
catch (DataBufferLimitException ex) {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void limitIgnored() {
|
||||
new LimitedDataBufferList(-1).add(toDataBuffer("123456"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearResetsCount() {
|
||||
LimitedDataBufferList list = new LimitedDataBufferList(5);
|
||||
list.add(toDataBuffer("12345"));
|
||||
list.clear();
|
||||
list.add(toDataBuffer("12345"));
|
||||
}
|
||||
|
||||
|
||||
private static DataBuffer toDataBuffer(String value) {
|
||||
return bufferFactory.wrap(value.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
}
|
||||
+32
-9
@@ -20,6 +20,7 @@ import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@@ -37,7 +38,7 @@ import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
@@ -70,7 +71,7 @@ public class AnnotationMetadataTests {
|
||||
@Test
|
||||
public void standardAnnotationMetadataForSubclass() {
|
||||
AnnotationMetadata metadata = new StandardAnnotationMetadata(AnnotatedComponentSubClass.class, true);
|
||||
doTestSubClassAnnotationInfo(metadata);
|
||||
doTestSubClassAnnotationInfo(metadata, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -78,10 +79,10 @@ public class AnnotationMetadataTests {
|
||||
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
|
||||
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotatedComponentSubClass.class.getName());
|
||||
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
|
||||
doTestSubClassAnnotationInfo(metadata);
|
||||
doTestSubClassAnnotationInfo(metadata, true);
|
||||
}
|
||||
|
||||
private void doTestSubClassAnnotationInfo(AnnotationMetadata metadata) {
|
||||
private void doTestSubClassAnnotationInfo(AnnotationMetadata metadata, boolean asm) {
|
||||
assertThat(metadata.getClassName(), is(AnnotatedComponentSubClass.class.getName()));
|
||||
assertThat(metadata.isInterface(), is(false));
|
||||
assertThat(metadata.isAnnotation(), is(false));
|
||||
@@ -93,11 +94,26 @@ public class AnnotationMetadataTests {
|
||||
assertThat(metadata.isAnnotated(Component.class.getName()), is(false));
|
||||
assertThat(metadata.isAnnotated(Scope.class.getName()), is(false));
|
||||
assertThat(metadata.isAnnotated(SpecialAttr.class.getName()), is(false));
|
||||
|
||||
if (asm) {
|
||||
assertThat(metadata.isAnnotated(NamedComposedAnnotation.class.getName()), is(false));
|
||||
assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName()), is(false));
|
||||
assertThat(metadata.getAnnotationTypes(), is(emptyCollectionOf(String.class)));
|
||||
}
|
||||
else {
|
||||
assertThat(metadata.isAnnotated(NamedComposedAnnotation.class.getName()), is(true));
|
||||
assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName()), is(true));
|
||||
assertThat(metadata.getAnnotationTypes(), containsInAnyOrder(NamedComposedAnnotation.class.getName()));
|
||||
}
|
||||
|
||||
assertThat(metadata.hasAnnotation(Component.class.getName()), is(false));
|
||||
assertThat(metadata.hasAnnotation(Scope.class.getName()), is(false));
|
||||
assertThat(metadata.hasAnnotation(SpecialAttr.class.getName()), is(false));
|
||||
assertThat(metadata.getAnnotationTypes().size(), is(0));
|
||||
assertThat(metadata.hasMetaAnnotation(Component.class.getName()), is(false));
|
||||
assertThat(metadata.hasMetaAnnotation(MetaAnnotation.class.getName()), is(false));
|
||||
assertThat(metadata.getAnnotationAttributes(Component.class.getName()), nullValue());
|
||||
assertThat(metadata.getAnnotationAttributes(MetaAnnotation.class.getName(), false), nullValue());
|
||||
assertThat(metadata.getAnnotationAttributes(MetaAnnotation.class.getName(), true), nullValue());
|
||||
assertThat(metadata.getAnnotatedMethods(DirectAnnotation.class.getName()).size(), equalTo(0));
|
||||
assertThat(metadata.isAnnotated(IsAnnotatedAnnotation.class.getName()), equalTo(false));
|
||||
assertThat(metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()), nullValue());
|
||||
@@ -262,13 +278,18 @@ public class AnnotationMetadataTests {
|
||||
assertThat(metadata.getInterfaceNames().length, is(1));
|
||||
assertThat(metadata.getInterfaceNames()[0], is(Serializable.class.getName()));
|
||||
|
||||
assertThat(metadata.isAnnotated(NamedComposedAnnotation.class.getName()), is(true));
|
||||
assertThat(metadata.isAnnotated(Component.class.getName()), is(true));
|
||||
assertThat(metadata.hasAnnotation(Component.class.getName()), is(true));
|
||||
assertThat(metadata.hasAnnotation(Scope.class.getName()), is(true));
|
||||
assertThat(metadata.hasAnnotation(SpecialAttr.class.getName()), is(true));
|
||||
assertThat(metadata.getAnnotationTypes().size(), is(6));
|
||||
assertThat(metadata.getAnnotationTypes().contains(Component.class.getName()), is(true));
|
||||
assertThat(metadata.getAnnotationTypes().contains(Scope.class.getName()), is(true));
|
||||
assertThat(metadata.getAnnotationTypes().contains(SpecialAttr.class.getName()), is(true));
|
||||
assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName()), is(true));
|
||||
assertThat(metadata.getAnnotationTypes(),
|
||||
containsInAnyOrder(Component.class.getName(), Scope.class.getName(),
|
||||
SpecialAttr.class.getName(), DirectAnnotation.class.getName(),
|
||||
MetaMetaAnnotation.class.getName(),
|
||||
EnumSubclasses.class.getName(),
|
||||
NamedComposedAnnotation.class.getName()));
|
||||
|
||||
AnnotationAttributes compAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(Component.class.getName());
|
||||
assertThat(compAttrs.size(), is(1));
|
||||
@@ -465,6 +486,7 @@ public class AnnotationMetadataTests {
|
||||
@DirectAnnotation(value = "direct", additional = "", additionalArray = {})
|
||||
@MetaMetaAnnotation
|
||||
@EnumSubclasses({SubclassEnum.FOO, SubclassEnum.BAR})
|
||||
@NamedComposedAnnotation
|
||||
private static class AnnotatedComponent implements Serializable {
|
||||
|
||||
@TestAutowired
|
||||
@@ -545,6 +567,7 @@ public class AnnotationMetadataTests {
|
||||
@NamedAnnotation3(name = "name 3")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Inherited
|
||||
public @interface NamedComposedAnnotation {
|
||||
}
|
||||
|
||||
|
||||
+70
-50
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.expression.spel.standard;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
@@ -65,15 +67,15 @@ public class SpelExpression implements Expression {
|
||||
|
||||
// Holds the compiled form of the expression (if it has been compiled)
|
||||
@Nullable
|
||||
private CompiledExpression compiledAst;
|
||||
private volatile CompiledExpression compiledAst;
|
||||
|
||||
// Count of many times as the expression been interpreted - can trigger compilation
|
||||
// when certain limit reached
|
||||
private volatile int interpretedCount = 0;
|
||||
private final AtomicInteger interpretedCount = new AtomicInteger(0);
|
||||
|
||||
// The number of times compilation was attempted and failed - enables us to eventually
|
||||
// give up trying to compile it when it just doesn't seem to be possible.
|
||||
private volatile int failedAttempts = 0;
|
||||
private final AtomicInteger failedAttempts = new AtomicInteger(0);
|
||||
|
||||
|
||||
/**
|
||||
@@ -116,16 +118,17 @@ public class SpelExpression implements Expression {
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getValue() throws EvaluationException {
|
||||
if (this.compiledAst != null) {
|
||||
CompiledExpression compiledAst = this.compiledAst;
|
||||
if (compiledAst != null) {
|
||||
try {
|
||||
EvaluationContext context = getEvaluationContext();
|
||||
return this.compiledAst.getValue(context.getRootObject().getValue(), context);
|
||||
return compiledAst.getValue(context.getRootObject().getValue(), context);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// If running in mixed mode, revert to interpreted
|
||||
if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
|
||||
this.interpretedCount = 0;
|
||||
this.compiledAst = null;
|
||||
this.interpretedCount.set(0);
|
||||
}
|
||||
else {
|
||||
// Running in SpelCompilerMode.immediate mode - propagate exception to caller
|
||||
@@ -144,10 +147,11 @@ public class SpelExpression implements Expression {
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> T getValue(@Nullable Class<T> expectedResultType) throws EvaluationException {
|
||||
if (this.compiledAst != null) {
|
||||
CompiledExpression compiledAst = this.compiledAst;
|
||||
if (compiledAst != null) {
|
||||
try {
|
||||
EvaluationContext context = getEvaluationContext();
|
||||
Object result = this.compiledAst.getValue(context.getRootObject().getValue(), context);
|
||||
Object result = compiledAst.getValue(context.getRootObject().getValue(), context);
|
||||
if (expectedResultType == null) {
|
||||
return (T) result;
|
||||
}
|
||||
@@ -159,8 +163,8 @@ public class SpelExpression implements Expression {
|
||||
catch (Throwable ex) {
|
||||
// If running in mixed mode, revert to interpreted
|
||||
if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
|
||||
this.interpretedCount = 0;
|
||||
this.compiledAst = null;
|
||||
this.interpretedCount.set(0);
|
||||
}
|
||||
else {
|
||||
// Running in SpelCompilerMode.immediate mode - propagate exception to caller
|
||||
@@ -179,15 +183,16 @@ public class SpelExpression implements Expression {
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getValue(Object rootObject) throws EvaluationException {
|
||||
if (this.compiledAst != null) {
|
||||
CompiledExpression compiledAst = this.compiledAst;
|
||||
if (compiledAst != null) {
|
||||
try {
|
||||
return this.compiledAst.getValue(rootObject, getEvaluationContext());
|
||||
return compiledAst.getValue(rootObject, getEvaluationContext());
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// If running in mixed mode, revert to interpreted
|
||||
if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
|
||||
this.interpretedCount = 0;
|
||||
this.compiledAst = null;
|
||||
this.interpretedCount.set(0);
|
||||
}
|
||||
else {
|
||||
// Running in SpelCompilerMode.immediate mode - propagate exception to caller
|
||||
@@ -207,9 +212,10 @@ public class SpelExpression implements Expression {
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> T getValue(Object rootObject, @Nullable Class<T> expectedResultType) throws EvaluationException {
|
||||
if (this.compiledAst != null) {
|
||||
CompiledExpression compiledAst = this.compiledAst;
|
||||
if (compiledAst != null) {
|
||||
try {
|
||||
Object result = this.compiledAst.getValue(rootObject, getEvaluationContext());
|
||||
Object result = compiledAst.getValue(rootObject, getEvaluationContext());
|
||||
if (expectedResultType == null) {
|
||||
return (T)result;
|
||||
}
|
||||
@@ -221,8 +227,8 @@ public class SpelExpression implements Expression {
|
||||
catch (Throwable ex) {
|
||||
// If running in mixed mode, revert to interpreted
|
||||
if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
|
||||
this.interpretedCount = 0;
|
||||
this.compiledAst = null;
|
||||
this.interpretedCount.set(0);
|
||||
}
|
||||
else {
|
||||
// Running in SpelCompilerMode.immediate mode - propagate exception to caller
|
||||
@@ -244,15 +250,16 @@ public class SpelExpression implements Expression {
|
||||
public Object getValue(EvaluationContext context) throws EvaluationException {
|
||||
Assert.notNull(context, "EvaluationContext is required");
|
||||
|
||||
if (this.compiledAst != null) {
|
||||
CompiledExpression compiledAst = this.compiledAst;
|
||||
if (compiledAst != null) {
|
||||
try {
|
||||
return this.compiledAst.getValue(context.getRootObject().getValue(), context);
|
||||
return compiledAst.getValue(context.getRootObject().getValue(), context);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// If running in mixed mode, revert to interpreted
|
||||
if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
|
||||
this.interpretedCount = 0;
|
||||
this.compiledAst = null;
|
||||
this.interpretedCount.set(0);
|
||||
}
|
||||
else {
|
||||
// Running in SpelCompilerMode.immediate mode - propagate exception to caller
|
||||
@@ -273,9 +280,10 @@ public class SpelExpression implements Expression {
|
||||
public <T> T getValue(EvaluationContext context, @Nullable Class<T> expectedResultType) throws EvaluationException {
|
||||
Assert.notNull(context, "EvaluationContext is required");
|
||||
|
||||
if (this.compiledAst != null) {
|
||||
CompiledExpression compiledAst = this.compiledAst;
|
||||
if (compiledAst != null) {
|
||||
try {
|
||||
Object result = this.compiledAst.getValue(context.getRootObject().getValue(), context);
|
||||
Object result = compiledAst.getValue(context.getRootObject().getValue(), context);
|
||||
if (expectedResultType != null) {
|
||||
return ExpressionUtils.convertTypedValue(context, new TypedValue(result), expectedResultType);
|
||||
}
|
||||
@@ -286,8 +294,8 @@ public class SpelExpression implements Expression {
|
||||
catch (Throwable ex) {
|
||||
// If running in mixed mode, revert to interpreted
|
||||
if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
|
||||
this.interpretedCount = 0;
|
||||
this.compiledAst = null;
|
||||
this.interpretedCount.set(0);
|
||||
}
|
||||
else {
|
||||
// Running in SpelCompilerMode.immediate mode - propagate exception to caller
|
||||
@@ -307,15 +315,16 @@ public class SpelExpression implements Expression {
|
||||
public Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException {
|
||||
Assert.notNull(context, "EvaluationContext is required");
|
||||
|
||||
if (this.compiledAst != null) {
|
||||
CompiledExpression compiledAst = this.compiledAst;
|
||||
if (compiledAst != null) {
|
||||
try {
|
||||
return this.compiledAst.getValue(rootObject, context);
|
||||
return compiledAst.getValue(rootObject, context);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// If running in mixed mode, revert to interpreted
|
||||
if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
|
||||
this.interpretedCount = 0;
|
||||
this.compiledAst = null;
|
||||
this.interpretedCount.set(0);
|
||||
}
|
||||
else {
|
||||
// Running in SpelCompilerMode.immediate mode - propagate exception to caller
|
||||
@@ -338,9 +347,10 @@ public class SpelExpression implements Expression {
|
||||
|
||||
Assert.notNull(context, "EvaluationContext is required");
|
||||
|
||||
if (this.compiledAst != null) {
|
||||
CompiledExpression compiledAst = this.compiledAst;
|
||||
if (compiledAst != null) {
|
||||
try {
|
||||
Object result = this.compiledAst.getValue(rootObject, context);
|
||||
Object result = compiledAst.getValue(rootObject, context);
|
||||
if (expectedResultType != null) {
|
||||
return ExpressionUtils.convertTypedValue(context, new TypedValue(result), expectedResultType);
|
||||
}
|
||||
@@ -351,8 +361,8 @@ public class SpelExpression implements Expression {
|
||||
catch (Throwable ex) {
|
||||
// If running in mixed mode, revert to interpreted
|
||||
if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
|
||||
this.interpretedCount = 0;
|
||||
this.compiledAst = null;
|
||||
this.interpretedCount.set(0);
|
||||
}
|
||||
else {
|
||||
// Running in SpelCompilerMode.immediate mode - propagate exception to caller
|
||||
@@ -473,48 +483,58 @@ public class SpelExpression implements Expression {
|
||||
* @param expressionState the expression state used to determine compilation mode
|
||||
*/
|
||||
private void checkCompile(ExpressionState expressionState) {
|
||||
this.interpretedCount++;
|
||||
this.interpretedCount.incrementAndGet();
|
||||
SpelCompilerMode compilerMode = expressionState.getConfiguration().getCompilerMode();
|
||||
if (compilerMode != SpelCompilerMode.OFF) {
|
||||
if (compilerMode == SpelCompilerMode.IMMEDIATE) {
|
||||
if (this.interpretedCount > 1) {
|
||||
if (this.interpretedCount.get() > 1) {
|
||||
compileExpression();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// compilerMode = SpelCompilerMode.MIXED
|
||||
if (this.interpretedCount > INTERPRETED_COUNT_THRESHOLD) {
|
||||
if (this.interpretedCount.get() > INTERPRETED_COUNT_THRESHOLD) {
|
||||
compileExpression();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform expression compilation. This will only succeed once exit descriptors for all nodes have
|
||||
* been determined. If the compilation fails and has failed more than 100 times the expression is
|
||||
* no longer considered suitable for compilation.
|
||||
* Perform expression compilation. This will only succeed once exit descriptors for
|
||||
* all nodes have been determined. If the compilation fails and has failed more than
|
||||
* 100 times the expression is no longer considered suitable for compilation.
|
||||
* @return whether this expression has been successfully compiled
|
||||
*/
|
||||
public boolean compileExpression() {
|
||||
if (this.failedAttempts > FAILED_ATTEMPTS_THRESHOLD) {
|
||||
CompiledExpression compiledAst = this.compiledAst;
|
||||
if (compiledAst != null) {
|
||||
// Previously compiled
|
||||
return true;
|
||||
}
|
||||
if (this.failedAttempts.get() > FAILED_ATTEMPTS_THRESHOLD) {
|
||||
// Don't try again
|
||||
return false;
|
||||
}
|
||||
if (this.compiledAst == null) {
|
||||
synchronized (this.expression) {
|
||||
// Possibly compiled by another thread before this thread got into the sync block
|
||||
if (this.compiledAst != null) {
|
||||
return true;
|
||||
}
|
||||
SpelCompiler compiler = SpelCompiler.getCompiler(this.configuration.getCompilerClassLoader());
|
||||
this.compiledAst = compiler.compile(this.ast);
|
||||
if (this.compiledAst == null) {
|
||||
this.failedAttempts++;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
if (this.compiledAst != null) {
|
||||
// Compiled by another thread before this thread got into the sync block
|
||||
return true;
|
||||
}
|
||||
SpelCompiler compiler = SpelCompiler.getCompiler(this.configuration.getCompilerClassLoader());
|
||||
compiledAst = compiler.compile(this.ast);
|
||||
if (compiledAst != null) {
|
||||
// Successfully compiled
|
||||
this.compiledAst = compiledAst;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// Failed to compile
|
||||
this.failedAttempts.incrementAndGet();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (this.compiledAst != null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -524,8 +544,8 @@ public class SpelExpression implements Expression {
|
||||
*/
|
||||
public void revertToInterpreted() {
|
||||
this.compiledAst = null;
|
||||
this.interpretedCount = 0;
|
||||
this.failedAttempts = 0;
|
||||
this.interpretedCount.set(0);
|
||||
this.failedAttempts.set(0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+7
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -55,6 +55,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
* @see StandardEvaluationContext
|
||||
* @see SimpleEvaluationContext
|
||||
@@ -765,8 +766,11 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||
}
|
||||
|
||||
if (this.member instanceof Method) {
|
||||
mv.visitMethodInsn((isStatic ? INVOKESTATIC : INVOKEVIRTUAL), classDesc, this.member.getName(),
|
||||
CodeFlow.createSignatureDescriptor((Method) this.member), false);
|
||||
Method method = (Method) this.member;
|
||||
boolean isInterface = method.getDeclaringClass().isInterface();
|
||||
int opcode = (isStatic ? INVOKESTATIC : isInterface ? INVOKEINTERFACE : INVOKEVIRTUAL);
|
||||
mv.visitMethodInsn(opcode, classDesc, method.getName(),
|
||||
CodeFlow.createSignatureDescriptor(method), isInterface);
|
||||
}
|
||||
else {
|
||||
mv.visitFieldInsn((isStatic ? GETSTATIC : GETFIELD), classDesc, this.member.getName(),
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.standard;
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.SpelCompilerMode;
|
||||
import org.springframework.expression.spel.SpelParserConfiguration;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests for the {@link SpelCompiler}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 5.1.14
|
||||
*/
|
||||
public class SpelCompilerTests {
|
||||
|
||||
@Test // gh-24357
|
||||
public void expressionCompilesWhenMethodComesFromPublicInterface() {
|
||||
SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null);
|
||||
SpelExpressionParser parser = new SpelExpressionParser(config);
|
||||
|
||||
OrderedComponent component = new OrderedComponent();
|
||||
Expression expression = parser.parseExpression("order");
|
||||
|
||||
// Evaluate the expression multiple times to ensure that it gets compiled.
|
||||
IntStream.rangeClosed(1, 5).forEach(i -> assertEquals(42, expression.getValue(component)));
|
||||
}
|
||||
|
||||
|
||||
static class OrderedComponent implements Ordered {
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -157,7 +157,12 @@ final class LogAdapter {
|
||||
private final ExtendedLogger logger;
|
||||
|
||||
public Log4jLog(String name) {
|
||||
this.logger = loggerContext.getLogger(name);
|
||||
LoggerContext context = loggerContext;
|
||||
if (context == null) {
|
||||
// Circular call in early-init scenario -> static field not initialized yet
|
||||
context = LogManager.getContext(Log4jLog.class.getClassLoader(), false);
|
||||
}
|
||||
this.logger = context.getLogger(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -280,92 +285,110 @@ final class LogAdapter {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFatalEnabled() {
|
||||
return isErrorEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled() {
|
||||
return this.logger.isErrorEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled() {
|
||||
return this.logger.isWarnEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled() {
|
||||
return this.logger.isInfoEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled() {
|
||||
return this.logger.isDebugEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled() {
|
||||
return this.logger.isTraceEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatal(Object message) {
|
||||
error(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatal(Object message, Throwable exception) {
|
||||
error(message, exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Object message) {
|
||||
if (message instanceof String || this.logger.isErrorEnabled()) {
|
||||
this.logger.error(String.valueOf(message));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Object message, Throwable exception) {
|
||||
if (message instanceof String || this.logger.isErrorEnabled()) {
|
||||
this.logger.error(String.valueOf(message), exception);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Object message) {
|
||||
if (message instanceof String || this.logger.isWarnEnabled()) {
|
||||
this.logger.warn(String.valueOf(message));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Object message, Throwable exception) {
|
||||
if (message instanceof String || this.logger.isWarnEnabled()) {
|
||||
this.logger.warn(String.valueOf(message), exception);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Object message) {
|
||||
if (message instanceof String || this.logger.isInfoEnabled()) {
|
||||
this.logger.info(String.valueOf(message));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Object message, Throwable exception) {
|
||||
if (message instanceof String || this.logger.isInfoEnabled()) {
|
||||
this.logger.info(String.valueOf(message), exception);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Object message) {
|
||||
if (message instanceof String || this.logger.isDebugEnabled()) {
|
||||
this.logger.debug(String.valueOf(message));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Object message, Throwable exception) {
|
||||
if (message instanceof String || this.logger.isDebugEnabled()) {
|
||||
this.logger.debug(String.valueOf(message), exception);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Object message) {
|
||||
if (message instanceof String || this.logger.isTraceEnabled()) {
|
||||
this.logger.trace(String.valueOf(message));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Object message, Throwable exception) {
|
||||
if (message instanceof String || this.logger.isTraceEnabled()) {
|
||||
this.logger.trace(String.valueOf(message), exception);
|
||||
@@ -486,74 +509,92 @@ final class LogAdapter {
|
||||
this.logger = java.util.logging.Logger.getLogger(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFatalEnabled() {
|
||||
return isErrorEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled() {
|
||||
return this.logger.isLoggable(java.util.logging.Level.SEVERE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled() {
|
||||
return this.logger.isLoggable(java.util.logging.Level.WARNING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled() {
|
||||
return this.logger.isLoggable(java.util.logging.Level.INFO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled() {
|
||||
return this.logger.isLoggable(java.util.logging.Level.FINE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled() {
|
||||
return this.logger.isLoggable(java.util.logging.Level.FINEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatal(Object message) {
|
||||
error(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatal(Object message, Throwable exception) {
|
||||
error(message, exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Object message) {
|
||||
log(java.util.logging.Level.SEVERE, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Object message, Throwable exception) {
|
||||
log(java.util.logging.Level.SEVERE, message, exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Object message) {
|
||||
log(java.util.logging.Level.WARNING, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Object message, Throwable exception) {
|
||||
log(java.util.logging.Level.WARNING, message, exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Object message) {
|
||||
log(java.util.logging.Level.INFO, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Object message, Throwable exception) {
|
||||
log(java.util.logging.Level.INFO, message, exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Object message) {
|
||||
log(java.util.logging.Level.FINE, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Object message, Throwable exception) {
|
||||
log(java.util.logging.Level.FINE, message, exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Object message) {
|
||||
log(java.util.logging.Level.FINEST, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Object message, Throwable exception) {
|
||||
log(java.util.logging.Level.FINEST, message, exception);
|
||||
}
|
||||
@@ -567,8 +608,8 @@ final class LogAdapter {
|
||||
else {
|
||||
rec = new LocationResolvingLogRecord(level, String.valueOf(message));
|
||||
rec.setLoggerName(this.name);
|
||||
rec.setResourceBundleName(logger.getResourceBundleName());
|
||||
rec.setResourceBundle(logger.getResourceBundle());
|
||||
rec.setResourceBundleName(this.logger.getResourceBundleName());
|
||||
rec.setResourceBundle(this.logger.getResourceBundle());
|
||||
rec.setThrown(exception);
|
||||
}
|
||||
logger.log(rec);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -220,6 +220,7 @@ public class SingleColumnRowMapper<T> implements RowMapper<T> {
|
||||
* (with the required type specified only once).
|
||||
* @param requiredType the type that each result object is expected to match
|
||||
* @since 4.1
|
||||
* @see #newInstance(Class, ConversionService)
|
||||
*/
|
||||
public static <T> SingleColumnRowMapper<T> newInstance(Class<T> requiredType) {
|
||||
return new SingleColumnRowMapper<>(requiredType);
|
||||
@@ -229,10 +230,15 @@ public class SingleColumnRowMapper<T> implements RowMapper<T> {
|
||||
* Static factory method to create a new {@code SingleColumnRowMapper}
|
||||
* (with the required type specified only once).
|
||||
* @param requiredType the type that each result object is expected to match
|
||||
* @param conversionService the {@link ConversionService} for converting a fetched value
|
||||
* @param conversionService the {@link ConversionService} for converting a
|
||||
* fetched value, or {@code null} for none
|
||||
* @since 5.0.4
|
||||
* @see #newInstance(Class)
|
||||
* @see #setConversionService
|
||||
*/
|
||||
public static <T> SingleColumnRowMapper<T> newInstance(Class<T> requiredType, @Nullable ConversionService conversionService) {
|
||||
public static <T> SingleColumnRowMapper<T> newInstance(
|
||||
Class<T> requiredType, @Nullable ConversionService conversionService) {
|
||||
|
||||
SingleColumnRowMapper<T> rowMapper = newInstance(requiredType);
|
||||
rowMapper.setConversionService(conversionService);
|
||||
return rowMapper;
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,8 +42,9 @@ public final class CallMetaDataProviderFactory {
|
||||
public static final List<String> supportedDatabaseProductsForProcedures = Arrays.asList(
|
||||
"Apache Derby",
|
||||
"DB2",
|
||||
"MySQL",
|
||||
"Informix Dynamic Server",
|
||||
"Microsoft SQL Server",
|
||||
"MySQL",
|
||||
"Oracle",
|
||||
"PostgreSQL",
|
||||
"Sybase"
|
||||
@@ -51,8 +52,8 @@ public final class CallMetaDataProviderFactory {
|
||||
|
||||
/** List of supported database products for function calls. */
|
||||
public static final List<String> supportedDatabaseProductsForFunctions = Arrays.asList(
|
||||
"MySQL",
|
||||
"Microsoft SQL Server",
|
||||
"MySQL",
|
||||
"Oracle",
|
||||
"PostgreSQL"
|
||||
);
|
||||
|
||||
+5
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -57,9 +57,12 @@ abstract class AbstractEmbeddedDatabaseConfigurer implements EmbeddedDatabaseCon
|
||||
try {
|
||||
con.close();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
catch (SQLException ex) {
|
||||
logger.debug("Could not close JDBC Connection on shutdown", ex);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Unexpected exception on closing JDBC Connection", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -52,10 +52,10 @@ public abstract class DatabasePopulatorUtils {
|
||||
DataSourceUtils.releaseConnection(connection, dataSource);
|
||||
}
|
||||
}
|
||||
catch (ScriptException ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
if (ex instanceof ScriptException) {
|
||||
throw (ScriptException) ex;
|
||||
}
|
||||
throw new UncategorizedScriptException("Failed to execute database script", ex);
|
||||
}
|
||||
}
|
||||
|
||||
+26
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,6 +29,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.jdbc.InvalidResultSetAccessException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* The default implementation of Spring's {@link SqlRowSet} interface, wrapping a
|
||||
@@ -160,6 +161,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getBigDecimal(int)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public BigDecimal getBigDecimal(int columnIndex) throws InvalidResultSetAccessException {
|
||||
try {
|
||||
return this.resultSet.getBigDecimal(columnIndex);
|
||||
@@ -173,6 +175,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getBigDecimal(String)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public BigDecimal getBigDecimal(String columnLabel) throws InvalidResultSetAccessException {
|
||||
return getBigDecimal(findColumn(columnLabel));
|
||||
}
|
||||
@@ -223,6 +226,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getDate(int)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Date getDate(int columnIndex) throws InvalidResultSetAccessException {
|
||||
try {
|
||||
return this.resultSet.getDate(columnIndex);
|
||||
@@ -236,6 +240,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getDate(String)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Date getDate(String columnLabel) throws InvalidResultSetAccessException {
|
||||
return getDate(findColumn(columnLabel));
|
||||
}
|
||||
@@ -244,6 +249,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getDate(int, Calendar)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Date getDate(int columnIndex, Calendar cal) throws InvalidResultSetAccessException {
|
||||
try {
|
||||
return this.resultSet.getDate(columnIndex, cal);
|
||||
@@ -257,6 +263,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getDate(String, Calendar)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Date getDate(String columnLabel, Calendar cal) throws InvalidResultSetAccessException {
|
||||
return getDate(findColumn(columnLabel), cal);
|
||||
}
|
||||
@@ -349,6 +356,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getNString(int)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public String getNString(int columnIndex) throws InvalidResultSetAccessException {
|
||||
try {
|
||||
return this.resultSet.getNString(columnIndex);
|
||||
@@ -362,6 +370,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getNString(String)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public String getNString(String columnLabel) throws InvalidResultSetAccessException {
|
||||
return getNString(findColumn(columnLabel));
|
||||
}
|
||||
@@ -370,6 +379,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getObject(int)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getObject(int columnIndex) throws InvalidResultSetAccessException {
|
||||
try {
|
||||
return this.resultSet.getObject(columnIndex);
|
||||
@@ -383,6 +393,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getObject(String)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getObject(String columnLabel) throws InvalidResultSetAccessException {
|
||||
return getObject(findColumn(columnLabel));
|
||||
}
|
||||
@@ -391,6 +402,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getObject(int, Map)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getObject(int columnIndex, Map<String, Class<?>> map) throws InvalidResultSetAccessException {
|
||||
try {
|
||||
return this.resultSet.getObject(columnIndex, map);
|
||||
@@ -404,6 +416,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getObject(String, Map)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getObject(String columnLabel, Map<String, Class<?>> map) throws InvalidResultSetAccessException {
|
||||
return getObject(findColumn(columnLabel), map);
|
||||
}
|
||||
@@ -412,6 +425,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getObject(int, Class)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> T getObject(int columnIndex, Class<T> type) throws InvalidResultSetAccessException {
|
||||
try {
|
||||
return this.resultSet.getObject(columnIndex, type);
|
||||
@@ -425,6 +439,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getObject(String, Class)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> T getObject(String columnLabel, Class<T> type) throws InvalidResultSetAccessException {
|
||||
return getObject(findColumn(columnLabel), type);
|
||||
}
|
||||
@@ -454,6 +469,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getString(int)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public String getString(int columnIndex) throws InvalidResultSetAccessException {
|
||||
try {
|
||||
return this.resultSet.getString(columnIndex);
|
||||
@@ -467,6 +483,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getString(String)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public String getString(String columnLabel) throws InvalidResultSetAccessException {
|
||||
return getString(findColumn(columnLabel));
|
||||
}
|
||||
@@ -475,6 +492,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getTime(int)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Time getTime(int columnIndex) throws InvalidResultSetAccessException {
|
||||
try {
|
||||
return this.resultSet.getTime(columnIndex);
|
||||
@@ -488,6 +506,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getTime(String)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Time getTime(String columnLabel) throws InvalidResultSetAccessException {
|
||||
return getTime(findColumn(columnLabel));
|
||||
}
|
||||
@@ -496,6 +515,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getTime(int, Calendar)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Time getTime(int columnIndex, Calendar cal) throws InvalidResultSetAccessException {
|
||||
try {
|
||||
return this.resultSet.getTime(columnIndex, cal);
|
||||
@@ -509,6 +529,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getTime(String, Calendar)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Time getTime(String columnLabel, Calendar cal) throws InvalidResultSetAccessException {
|
||||
return getTime(findColumn(columnLabel), cal);
|
||||
}
|
||||
@@ -517,6 +538,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getTimestamp(int)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Timestamp getTimestamp(int columnIndex) throws InvalidResultSetAccessException {
|
||||
try {
|
||||
return this.resultSet.getTimestamp(columnIndex);
|
||||
@@ -530,6 +552,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getTimestamp(String)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Timestamp getTimestamp(String columnLabel) throws InvalidResultSetAccessException {
|
||||
return getTimestamp(findColumn(columnLabel));
|
||||
}
|
||||
@@ -538,6 +561,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getTimestamp(int, Calendar)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Timestamp getTimestamp(int columnIndex, Calendar cal) throws InvalidResultSetAccessException {
|
||||
try {
|
||||
return this.resultSet.getTimestamp(columnIndex, cal);
|
||||
@@ -551,6 +575,7 @@ public class ResultSetWrappingSqlRowSet implements SqlRowSet {
|
||||
* @see java.sql.ResultSet#getTimestamp(String, Calendar)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Timestamp getTimestamp(String columnLabel, Calendar cal) throws InvalidResultSetAccessException {
|
||||
return getTimestamp(findColumn(columnLabel), cal);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,6 +25,7 @@ import java.util.Calendar;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.jdbc.InvalidResultSetAccessException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Mirror interface for {@link javax.sql.RowSet}, representing a disconnected variant of
|
||||
@@ -74,6 +75,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return an BigDecimal object representing the column value
|
||||
* @see java.sql.ResultSet#getBigDecimal(int)
|
||||
*/
|
||||
@Nullable
|
||||
BigDecimal getBigDecimal(int columnIndex) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -82,6 +84,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return an BigDecimal object representing the column value
|
||||
* @see java.sql.ResultSet#getBigDecimal(String)
|
||||
*/
|
||||
@Nullable
|
||||
BigDecimal getBigDecimal(String columnLabel) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -122,6 +125,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Date object representing the column value
|
||||
* @see java.sql.ResultSet#getDate(int)
|
||||
*/
|
||||
@Nullable
|
||||
Date getDate(int columnIndex) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -130,6 +134,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Date object representing the column value
|
||||
* @see java.sql.ResultSet#getDate(String)
|
||||
*/
|
||||
@Nullable
|
||||
Date getDate(String columnLabel) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -139,6 +144,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Date object representing the column value
|
||||
* @see java.sql.ResultSet#getDate(int, Calendar)
|
||||
*/
|
||||
@Nullable
|
||||
Date getDate(int columnIndex, Calendar cal) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -148,6 +154,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Date object representing the column value
|
||||
* @see java.sql.ResultSet#getDate(String, Calendar)
|
||||
*/
|
||||
@Nullable
|
||||
Date getDate(String columnLabel, Calendar cal) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -222,6 +229,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @since 4.1.3
|
||||
* @see java.sql.ResultSet#getNString(int)
|
||||
*/
|
||||
@Nullable
|
||||
String getNString(int columnIndex) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -232,6 +240,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @since 4.1.3
|
||||
* @see java.sql.ResultSet#getNString(String)
|
||||
*/
|
||||
@Nullable
|
||||
String getNString(String columnLabel) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -240,6 +249,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Object representing the column value
|
||||
* @see java.sql.ResultSet#getObject(int)
|
||||
*/
|
||||
@Nullable
|
||||
Object getObject(int columnIndex) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -248,6 +258,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Object representing the column value
|
||||
* @see java.sql.ResultSet#getObject(String)
|
||||
*/
|
||||
@Nullable
|
||||
Object getObject(String columnLabel) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -257,6 +268,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Object representing the column value
|
||||
* @see java.sql.ResultSet#getObject(int, Map)
|
||||
*/
|
||||
@Nullable
|
||||
Object getObject(int columnIndex, Map<String, Class<?>> map) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -266,6 +278,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Object representing the column value
|
||||
* @see java.sql.ResultSet#getObject(String, Map)
|
||||
*/
|
||||
@Nullable
|
||||
Object getObject(String columnLabel, Map<String, Class<?>> map) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -273,9 +286,10 @@ public interface SqlRowSet extends Serializable {
|
||||
* @param columnIndex the column index
|
||||
* @param type the Java type to convert the designated column to
|
||||
* @return a Object representing the column value
|
||||
* @see java.sql.ResultSet#getObject(int)
|
||||
* @since 4.1.3
|
||||
* @see java.sql.ResultSet#getObject(int, Class)
|
||||
*/
|
||||
@Nullable
|
||||
<T> T getObject(int columnIndex, Class<T> type) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -283,9 +297,10 @@ public interface SqlRowSet extends Serializable {
|
||||
* @param columnLabel the column label
|
||||
* @param type the Java type to convert the designated column to
|
||||
* @return a Object representing the column value
|
||||
* @see java.sql.ResultSet#getObject(int)
|
||||
* @since 4.1.3
|
||||
* @see java.sql.ResultSet#getObject(String, Class)
|
||||
*/
|
||||
@Nullable
|
||||
<T> T getObject(String columnLabel, Class<T> type) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -310,6 +325,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a String representing the column value
|
||||
* @see java.sql.ResultSet#getString(int)
|
||||
*/
|
||||
@Nullable
|
||||
String getString(int columnIndex) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -318,6 +334,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a String representing the column value
|
||||
* @see java.sql.ResultSet#getString(String)
|
||||
*/
|
||||
@Nullable
|
||||
String getString(String columnLabel) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -326,6 +343,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Time object representing the column value
|
||||
* @see java.sql.ResultSet#getTime(int)
|
||||
*/
|
||||
@Nullable
|
||||
Time getTime(int columnIndex) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -334,6 +352,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Time object representing the column value
|
||||
* @see java.sql.ResultSet#getTime(String)
|
||||
*/
|
||||
@Nullable
|
||||
Time getTime(String columnLabel) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -343,6 +362,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Time object representing the column value
|
||||
* @see java.sql.ResultSet#getTime(int, Calendar)
|
||||
*/
|
||||
@Nullable
|
||||
Time getTime(int columnIndex, Calendar cal) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -352,6 +372,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Time object representing the column value
|
||||
* @see java.sql.ResultSet#getTime(String, Calendar)
|
||||
*/
|
||||
@Nullable
|
||||
Time getTime(String columnLabel, Calendar cal) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -360,6 +381,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Timestamp object representing the column value
|
||||
* @see java.sql.ResultSet#getTimestamp(int)
|
||||
*/
|
||||
@Nullable
|
||||
Timestamp getTimestamp(int columnIndex) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -368,6 +390,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Timestamp object representing the column value
|
||||
* @see java.sql.ResultSet#getTimestamp(String)
|
||||
*/
|
||||
@Nullable
|
||||
Timestamp getTimestamp(String columnLabel) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -377,6 +400,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Timestamp object representing the column value
|
||||
* @see java.sql.ResultSet#getTimestamp(int, Calendar)
|
||||
*/
|
||||
@Nullable
|
||||
Timestamp getTimestamp(int columnIndex, Calendar cal) throws InvalidResultSetAccessException;
|
||||
|
||||
/**
|
||||
@@ -386,6 +410,7 @@ public interface SqlRowSet extends Serializable {
|
||||
* @return a Timestamp object representing the column value
|
||||
* @see java.sql.ResultSet#getTimestamp(String, Calendar)
|
||||
*/
|
||||
@Nullable
|
||||
Timestamp getTimestamp(String columnLabel, Calendar cal) throws InvalidResultSetAccessException;
|
||||
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
<value>1</value>
|
||||
</property>
|
||||
<property name="cannotAcquireLockCodes">
|
||||
<value>1205</value>
|
||||
<value>1205,3572</value>
|
||||
</property>
|
||||
<property name="deadlockLoserCodes">
|
||||
<value>1213</value>
|
||||
|
||||
+6
@@ -858,6 +858,7 @@ public class DataSourceTransactionManagerTests {
|
||||
public void testTransactionWithIsolationAndReadOnly() throws Exception {
|
||||
given(con.getTransactionIsolation()).willReturn(Connection.TRANSACTION_READ_COMMITTED);
|
||||
given(con.getAutoCommit()).willReturn(true);
|
||||
given(con.isReadOnly()).willReturn(true);
|
||||
|
||||
TransactionTemplate tt = new TransactionTemplate(tm);
|
||||
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
@@ -875,11 +876,13 @@ public class DataSourceTransactionManagerTests {
|
||||
|
||||
assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
|
||||
InOrder ordered = inOrder(con);
|
||||
ordered.verify(con).setReadOnly(true);
|
||||
ordered.verify(con).setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
|
||||
ordered.verify(con).setAutoCommit(false);
|
||||
ordered.verify(con).commit();
|
||||
ordered.verify(con).setAutoCommit(true);
|
||||
ordered.verify(con).setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
|
||||
ordered.verify(con).setReadOnly(false);
|
||||
verify(con).close();
|
||||
}
|
||||
|
||||
@@ -890,6 +893,7 @@ public class DataSourceTransactionManagerTests {
|
||||
given(con.getAutoCommit()).willReturn(true);
|
||||
Statement stmt = mock(Statement.class);
|
||||
given(con.createStatement()).willReturn(stmt);
|
||||
given(con.isReadOnly()).willReturn(true);
|
||||
|
||||
TransactionTemplate tt = new TransactionTemplate(tm);
|
||||
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
@@ -906,11 +910,13 @@ public class DataSourceTransactionManagerTests {
|
||||
|
||||
assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
|
||||
InOrder ordered = inOrder(con, stmt);
|
||||
ordered.verify(con).setReadOnly(true);
|
||||
ordered.verify(con).setAutoCommit(false);
|
||||
ordered.verify(stmt).executeUpdate("SET TRANSACTION READ ONLY");
|
||||
ordered.verify(stmt).close();
|
||||
ordered.verify(con).commit();
|
||||
ordered.verify(con).setAutoCommit(true);
|
||||
ordered.verify(con).setReadOnly(false);
|
||||
ordered.verify(con).close();
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ class CachedMessageProducer implements MessageProducer, QueueSender, TopicPublis
|
||||
return this.target.getDisableMessageTimestamp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeliveryDelay(long deliveryDelay) throws JMSException {
|
||||
if (this.originalDeliveryDelay == null) {
|
||||
this.originalDeliveryDelay = this.target.getDeliveryDelay();
|
||||
@@ -96,6 +97,7 @@ class CachedMessageProducer implements MessageProducer, QueueSender, TopicPublis
|
||||
this.target.setDeliveryDelay(deliveryDelay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDeliveryDelay() throws JMSException {
|
||||
return this.target.getDeliveryDelay();
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -505,7 +505,7 @@ public class SingleConnectionFactory implements ConnectionFactory, QueueConnecti
|
||||
logger.debug("Ignoring Connection state exception - assuming already closed: " + ex);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Could not close shared JMS Connection", ex);
|
||||
logger.warn("Could not close shared JMS Connection", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -340,7 +340,7 @@ public class MappingJackson2MessageConverter implements SmartMessageConverter, B
|
||||
* sets the resulting value (either a mapped id or the raw Java class name)
|
||||
* into the configured type id message property.
|
||||
* @param object the payload object to set a type id for
|
||||
* @param message the JMS Message to set the type id on
|
||||
* @param message the JMS Message on which to set the type id property
|
||||
* @throws JMSException if thrown by JMS methods
|
||||
* @see #getJavaTypeForMessage(javax.jms.Message)
|
||||
* @see #setTypeIdPropertyName(String)
|
||||
@@ -442,7 +442,7 @@ public class MappingJackson2MessageConverter implements SmartMessageConverter, B
|
||||
* <p>The default implementation parses the configured type id property name
|
||||
* and consults the configured type id mapping. This can be overridden with
|
||||
* a different strategy, e.g. doing some heuristics based on message origin.
|
||||
* @param message the JMS Message to set the type id on
|
||||
* @param message the JMS Message from which to get the type id property
|
||||
* @throws JMSException if thrown by JMS methods
|
||||
* @see #setTypeIdOnMessage(Object, javax.jms.Message)
|
||||
* @see #setTypeIdPropertyName(String)
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -41,6 +41,6 @@ public enum SimpMessageType {
|
||||
|
||||
DISCONNECT_ACK,
|
||||
|
||||
OTHER;
|
||||
OTHER
|
||||
|
||||
}
|
||||
|
||||
-1
@@ -560,7 +560,6 @@ public class MultiServerUserRegistry implements SimpUserRegistry, SmartApplicati
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ dependencies {
|
||||
optional(project(":spring-context"))
|
||||
optional(project(":spring-web"))
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.4")
|
||||
optional("org.hibernate:hibernate-core:5.3.12.Final")
|
||||
optional("org.hibernate:hibernate-core:5.3.15.Final")
|
||||
optional("javax.servlet:javax.servlet-api:3.1.0")
|
||||
testCompile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
|
||||
+2
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -170,11 +170,8 @@ public abstract class SessionFactoryUtils {
|
||||
try {
|
||||
session.close();
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
logger.debug("Could not close Hibernate Session", ex);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Unexpected exception on closing Hibernate Session", ex);
|
||||
logger.error("Failed to release Hibernate Session", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -427,11 +427,8 @@ public abstract class EntityManagerFactoryUtils {
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
catch (PersistenceException ex) {
|
||||
logger.debug("Could not close JPA EntityManager", ex);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Unexpected exception on closing JPA EntityManager", ex);
|
||||
logger.error("Failed to release JPA EntityManager", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -603,9 +603,9 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager
|
||||
getJpaDialect().releaseJdbcConnection(conHandle,
|
||||
txObject.getEntityManagerHolder().getEntityManager());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
catch (Throwable ex) {
|
||||
// Just log it, to keep a transaction-related exception.
|
||||
logger.error("Could not close JDBC connection after transaction", ex);
|
||||
logger.error("Failed to release JDBC connection after transaction", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,5 +18,5 @@ package org.springframework.orm.jpa.hibernate.beans;
|
||||
|
||||
public enum BeanSource {
|
||||
SPRING,
|
||||
FALLBACK;
|
||||
FALLBACK
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ dependencies {
|
||||
testCompile("javax.ejb:javax.ejb-api:3.2")
|
||||
testCompile("javax.interceptor:javax.interceptor-api:1.2.2")
|
||||
testCompile("javax.mail:javax.mail-api:1.6.2")
|
||||
testCompile("org.hibernate:hibernate-core:5.3.12.Final")
|
||||
testCompile("org.hibernate:hibernate-validator:6.0.17.Final")
|
||||
testCompile("org.hibernate:hibernate-core:5.3.15.Final")
|
||||
testCompile("org.hibernate:hibernate-validator:6.0.18.Final")
|
||||
// Enable use of the JUnit Platform Runner
|
||||
testCompile("org.junit.platform:junit-platform-runner")
|
||||
testCompile("org.junit.jupiter:junit-jupiter-params")
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package org.springframework.mock.web;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -28,6 +32,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Vedran Pavic
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 5.1
|
||||
*/
|
||||
public class MockCookie extends Cookie {
|
||||
@@ -35,12 +40,15 @@ public class MockCookie extends Cookie {
|
||||
private static final long serialVersionUID = 4312531139502726325L;
|
||||
|
||||
|
||||
@Nullable
|
||||
private ZonedDateTime expires;
|
||||
|
||||
@Nullable
|
||||
private String sameSite;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor with the cookie name and value.
|
||||
* Construct a new {@link MockCookie} with the supplied name and value.
|
||||
* @param name the name
|
||||
* @param value the value
|
||||
* @see Cookie#Cookie(String, String)
|
||||
@@ -49,12 +57,29 @@ public class MockCookie extends Cookie {
|
||||
super(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the "Expires" attribute for this cookie.
|
||||
* @since 5.1.11
|
||||
*/
|
||||
public void setExpires(@Nullable ZonedDateTime expires) {
|
||||
this.expires = expires;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the "SameSite" attribute to the cookie.
|
||||
* Get the "Expires" attribute for this cookie.
|
||||
* @since 5.1.11
|
||||
* @return the "Expires" attribute for this cookie, or {@code null} if not set
|
||||
*/
|
||||
@Nullable
|
||||
public ZonedDateTime getExpires() {
|
||||
return this.expires;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the "SameSite" attribute for this cookie.
|
||||
* <p>This limits the scope of the cookie such that it will only be attached
|
||||
* to same site requests if {@code "Strict"} or cross-site requests if
|
||||
* {@code "Lax"}.
|
||||
* to same-site requests if the supplied value is {@code "Strict"} or cross-site
|
||||
* requests if the supplied value is {@code "Lax"}.
|
||||
* @see <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis#section-4.1.2.7">RFC6265 bis</a>
|
||||
*/
|
||||
public void setSameSite(@Nullable String sameSite) {
|
||||
@@ -62,7 +87,8 @@ public class MockCookie extends Cookie {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the "SameSite" attribute, or {@code null} if not set.
|
||||
* Get the "SameSite" attribute for this cookie.
|
||||
* @return the "SameSite" attribute for this cookie, or {@code null} if not set
|
||||
*/
|
||||
@Nullable
|
||||
public String getSameSite() {
|
||||
@@ -71,7 +97,7 @@ public class MockCookie extends Cookie {
|
||||
|
||||
|
||||
/**
|
||||
* Factory method that parses the value of a "Set-Cookie" header.
|
||||
* Factory method that parses the value of the supplied "Set-Cookie" header.
|
||||
* @param setCookieHeader the "Set-Cookie" value; never {@code null} or empty
|
||||
* @return the created cookie
|
||||
*/
|
||||
@@ -94,6 +120,15 @@ public class MockCookie extends Cookie {
|
||||
else if (StringUtils.startsWithIgnoreCase(attribute, "Max-Age")) {
|
||||
cookie.setMaxAge(Integer.parseInt(extractAttributeValue(attribute, setCookieHeader)));
|
||||
}
|
||||
else if (StringUtils.startsWithIgnoreCase(attribute, "Expires")) {
|
||||
try {
|
||||
cookie.setExpires(ZonedDateTime.parse(extractAttributeValue(attribute, setCookieHeader),
|
||||
DateTimeFormatter.RFC_1123_DATE_TIME));
|
||||
}
|
||||
catch (DateTimeException ex) {
|
||||
// ignore invalid date formats
|
||||
}
|
||||
}
|
||||
else if (StringUtils.startsWithIgnoreCase(attribute, "Path")) {
|
||||
cookie.setPath(extractAttributeValue(attribute, setCookieHeader));
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user