mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
156 Commits
main
...
v5.1.15.RELEASE
| Author | SHA1 | Date | |
|---|---|---|---|
| 0f95a01131 | |||
| a4cc16051c | |||
| c8b49346b1 | |||
| 34b9ca310d | |||
| ea7b0103c5 | |||
| e3175a2dc9 | |||
| 91316dc11b | |||
| ac8d1df3ab | |||
| f023df703a | |||
| 9ab7cde00e | |||
| fad9b509ab | |||
| 5ddbefecea | |||
| a4bba6aff2 | |||
| 906583c40a | |||
| 3689b3fdd5 | |||
| 4a5bac97b5 | |||
| 45a270b71f | |||
| ef013f7158 | |||
| 818d18aa09 | |||
| 4715ad242e | |||
| e51f660286 | |||
| 9f71c98871 | |||
| dbb09334f3 | |||
| 5953d99d1c | |||
| c9be4f6874 | |||
| fbc63b0e32 | |||
| 5f7df0d14f | |||
| ee832206dc | |||
| 1e295c7bbb | |||
| 4fbba931a5 | |||
| 86f19f6cb6 | |||
| 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
|
||||
|
||||
+12
-12
@@ -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.28.v20200408"
|
||||
junit5Version = "5.3.2"
|
||||
kotlinVersion = "1.2.71"
|
||||
log4jVersion = "2.11.2"
|
||||
nettyVersion = "4.1.43.Final"
|
||||
reactorVersion = "Californium-SR13"
|
||||
nettyVersion = "4.1.49.Final"
|
||||
reactorVersion = "Californium-SR18"
|
||||
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.19"
|
||||
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.34"
|
||||
undertowVersion = "2.0.30.Final"
|
||||
|
||||
gradleScriptDir = "${rootProject.projectDir}/gradle"
|
||||
withoutJclOverSlf4j = {
|
||||
@@ -142,13 +142,13 @@ configure(allprojects) { project ->
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
toolVersion = "8.24"
|
||||
toolVersion = "8.31"
|
||||
configDir = rootProject.file("src/checkstyle")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url "https://repo.spring.io/libs-release" }
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -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.15.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")
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -258,15 +258,17 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
int mod = method.getModifiers();
|
||||
if (!Modifier.isStatic(mod) && !Modifier.isPrivate(mod)) {
|
||||
if (Modifier.isFinal(mod)) {
|
||||
if (implementsInterface(method, ifcs)) {
|
||||
if (logger.isInfoEnabled() && implementsInterface(method, ifcs)) {
|
||||
logger.info("Unable to proxy interface-implementing method [" + method + "] because " +
|
||||
"it is marked as final: Consider using interface-based JDK proxies instead!");
|
||||
}
|
||||
logger.debug("Final method [" + method + "] cannot get proxied via CGLIB: " +
|
||||
"Calls to this method will NOT be routed to the target instance and " +
|
||||
"might lead to NPEs against uninitialized fields in the proxy instance.");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Final method [" + method + "] cannot get proxied via CGLIB: " +
|
||||
"Calls to this method will NOT be routed to the target instance and " +
|
||||
"might lead to NPEs against uninitialized fields in the proxy instance.");
|
||||
}
|
||||
}
|
||||
else if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod) &&
|
||||
else if (logger.isDebugEnabled() && !Modifier.isPublic(mod) && !Modifier.isProtected(mod) &&
|
||||
proxyClassLoader != null && proxySuperClass.getClassLoader() != proxyClassLoader) {
|
||||
logger.debug("Method [" + method + "] is package-visible across different ClassLoaders " +
|
||||
"and cannot get proxied via CGLIB: Declare this method as public or protected " +
|
||||
@@ -526,7 +528,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
private static class StaticDispatcher implements Dispatcher, Serializable {
|
||||
|
||||
@Nullable
|
||||
private Object target;
|
||||
private final Object target;
|
||||
|
||||
public StaticDispatcher(@Nullable Object target) {
|
||||
this.target = target;
|
||||
@@ -552,7 +554,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object loadObject() throws Exception {
|
||||
public Object loadObject() {
|
||||
return this.advised;
|
||||
}
|
||||
}
|
||||
@@ -940,11 +942,11 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean equalsAdviceClasses(Advisor a, Advisor b) {
|
||||
private static boolean equalsAdviceClasses(Advisor a, Advisor b) {
|
||||
return (a.getAdvice().getClass() == b.getAdvice().getClass());
|
||||
}
|
||||
|
||||
private boolean equalsPointcuts(Advisor a, Advisor b) {
|
||||
private static boolean equalsPointcuts(Advisor a, Advisor b) {
|
||||
// If only one of the advisor (but not both) is PointcutAdvisor, then it is a mismatch.
|
||||
// Takes care of the situations where an IntroductionAdvisor is used (see SPR-3959).
|
||||
return (!(a instanceof PointcutAdvisor) ||
|
||||
|
||||
@@ -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.
|
||||
@@ -21,9 +21,7 @@ import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.aopalliance.intercept.Interceptor;
|
||||
@@ -342,11 +340,8 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
|
||||
// an independent instance of the configuration.
|
||||
// In this case, no proxy will have an instance of this object's configuration,
|
||||
// but will have an independent copy.
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Creating copy of prototype ProxyFactoryBean config: " + this);
|
||||
}
|
||||
|
||||
ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());
|
||||
|
||||
// The copy needs a fresh advisor chain, and a fresh TargetSource.
|
||||
TargetSource targetSource = freshTargetSource();
|
||||
copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
|
||||
@@ -359,9 +354,6 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
|
||||
}
|
||||
copy.setFrozen(this.freezeProxy);
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Using ProxyCreatorSupport copy: " + copy);
|
||||
}
|
||||
return getProxy(copy.createAopProxy());
|
||||
}
|
||||
|
||||
@@ -395,9 +387,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
|
||||
logger.debug("Bean with name '" + finalName + "' concluding interceptor chain " +
|
||||
"is not an advisor class: treating it as a target or TargetSource");
|
||||
}
|
||||
String[] newNames = new String[this.interceptorNames.length - 1];
|
||||
System.arraycopy(this.interceptorNames, 0, newNames, 0, newNames.length);
|
||||
this.interceptorNames = newNames;
|
||||
this.interceptorNames = Arrays.copyOf(this.interceptorNames, this.interceptorNames.length - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -449,16 +439,12 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
|
||||
|
||||
// Materialize interceptor chain from bean names.
|
||||
for (String name : this.interceptorNames) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Configuring advisor or advice '" + name + "'");
|
||||
}
|
||||
|
||||
if (name.endsWith(GLOBAL_SUFFIX)) {
|
||||
if (!(this.beanFactory instanceof ListableBeanFactory)) {
|
||||
throw new AopConfigException(
|
||||
"Can only use global advisors or interceptors with a ListableBeanFactory");
|
||||
}
|
||||
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
|
||||
addGlobalAdvisors((ListableBeanFactory) this.beanFactory,
|
||||
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
|
||||
}
|
||||
|
||||
@@ -475,7 +461,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
|
||||
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
|
||||
advice = new PrototypePlaceholderAdvisor(name);
|
||||
}
|
||||
addAdvisorOnChainCreation(advice, name);
|
||||
addAdvisorOnChainCreation(advice);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -498,11 +484,10 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Refreshing bean named '" + pa.getBeanName() + "'");
|
||||
}
|
||||
// Replace the placeholder with a fresh prototype instance resulting
|
||||
// from a getBean() lookup
|
||||
// Replace the placeholder with a fresh prototype instance resulting from a getBean lookup
|
||||
if (this.beanFactory == null) {
|
||||
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
|
||||
"- cannot resolve prototype advisor '" + pa.getBeanName() + "'");
|
||||
throw new IllegalStateException("No BeanFactory available anymore (probably due to " +
|
||||
"serialization) - cannot resolve prototype advisor '" + pa.getBeanName() + "'");
|
||||
}
|
||||
Object bean = this.beanFactory.getBean(pa.getBeanName());
|
||||
Advisor refreshedAdvisor = namedBeanToAdvisor(bean);
|
||||
@@ -519,28 +504,26 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
|
||||
/**
|
||||
* Add all global interceptors and pointcuts.
|
||||
*/
|
||||
private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) {
|
||||
private void addGlobalAdvisors(ListableBeanFactory beanFactory, String prefix) {
|
||||
String[] globalAdvisorNames =
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Advisor.class);
|
||||
String[] globalInterceptorNames =
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Interceptor.class);
|
||||
List<Object> beans = new ArrayList<>(globalAdvisorNames.length + globalInterceptorNames.length);
|
||||
Map<Object, String> names = new HashMap<>(beans.size());
|
||||
for (String name : globalAdvisorNames) {
|
||||
Object bean = beanFactory.getBean(name);
|
||||
beans.add(bean);
|
||||
names.put(bean, name);
|
||||
}
|
||||
for (String name : globalInterceptorNames) {
|
||||
Object bean = beanFactory.getBean(name);
|
||||
beans.add(bean);
|
||||
names.put(bean, name);
|
||||
}
|
||||
AnnotationAwareOrderComparator.sort(beans);
|
||||
for (Object bean : beans) {
|
||||
String name = names.get(bean);
|
||||
if (name.startsWith(prefix)) {
|
||||
addAdvisorOnChainCreation(bean, name);
|
||||
if (globalAdvisorNames.length > 0 || globalInterceptorNames.length > 0) {
|
||||
List<Object> beans = new ArrayList<>(globalAdvisorNames.length + globalInterceptorNames.length);
|
||||
for (String name : globalAdvisorNames) {
|
||||
if (name.startsWith(prefix)) {
|
||||
beans.add(beanFactory.getBean(name));
|
||||
}
|
||||
}
|
||||
for (String name : globalInterceptorNames) {
|
||||
if (name.startsWith(prefix)) {
|
||||
beans.add(beanFactory.getBean(name));
|
||||
}
|
||||
}
|
||||
AnnotationAwareOrderComparator.sort(beans);
|
||||
for (Object bean : beans) {
|
||||
addAdvisorOnChainCreation(bean);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -551,17 +534,11 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
|
||||
* Because of these three possibilities, we can't type the signature
|
||||
* more strongly.
|
||||
* @param next advice, advisor or target object
|
||||
* @param name bean name from which we obtained this object in our owning
|
||||
* bean factory
|
||||
*/
|
||||
private void addAdvisorOnChainCreation(Object next, String name) {
|
||||
private void addAdvisorOnChainCreation(Object next) {
|
||||
// We need to convert to an Advisor if necessary so that our source reference
|
||||
// matches what we find from superclass interceptors.
|
||||
Advisor advisor = namedBeanToAdvisor(next);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Adding advisor with name '" + name + "'");
|
||||
}
|
||||
addAdvisor(advisor);
|
||||
addAdvisor(namedBeanToAdvisor(next));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -572,9 +549,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
|
||||
*/
|
||||
private TargetSource freshTargetSource() {
|
||||
if (this.targetName == null) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Not refreshing target: Bean name not specified in 'interceptorNames'.");
|
||||
}
|
||||
// Not refreshing target: bean name not specified in 'interceptorNames'
|
||||
return this.targetSource;
|
||||
}
|
||||
else {
|
||||
@@ -602,8 +577,8 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
|
||||
// We expected this to be an Advisor or Advice,
|
||||
// but it wasn't. This is a configuration error.
|
||||
throw new AopConfigException("Unknown advisor type " + next.getClass() +
|
||||
"; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry," +
|
||||
"which may also be target or TargetSource", ex);
|
||||
"; can only include Advisor or Advice type beans in interceptorNames chain " +
|
||||
"except for last entry which may also be target instance or TargetSource", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -614,7 +589,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
|
||||
protected void adviceChanged() {
|
||||
super.adviceChanged();
|
||||
if (this.singleton) {
|
||||
logger.debug("Advice has changed; recaching singleton instance");
|
||||
logger.debug("Advice has changed; re-caching singleton instance");
|
||||
synchronized (this) {
|
||||
this.singletonInstance = null;
|
||||
}
|
||||
|
||||
+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();
|
||||
|
||||
@@ -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.
|
||||
@@ -39,10 +39,16 @@ import org.springframework.lang.Nullable;
|
||||
*
|
||||
* <p><b>{@code FactoryBean} is a programmatic contract. Implementations are not
|
||||
* supposed to rely on annotation-driven injection or other reflective facilities.</b>
|
||||
* {@link #getObjectType()} {@link #getObject()} invocations may arrive early in
|
||||
* the bootstrap process, even ahead of any post-processor setup. If you need access
|
||||
* {@link #getObjectType()} {@link #getObject()} invocations may arrive early in the
|
||||
* bootstrap process, even ahead of any post-processor setup. If you need access to
|
||||
* other beans, implement {@link BeanFactoryAware} and obtain them programmatically.
|
||||
*
|
||||
* <p><b>The container is only responsible for managing the lifecycle of the FactoryBean
|
||||
* instance, not the lifecycle of the objects created by the FactoryBean.</b> Therefore,
|
||||
* a destroy method on an exposed bean object (such as {@link java.io.Closeable#close()}
|
||||
* will <i>not</i> be called automatically. Instead, a FactoryBean should implement
|
||||
* {@link DisposableBean} and delegate any such close call to the underlying object.
|
||||
*
|
||||
* <p>Finally, FactoryBean objects participate in the containing BeanFactory's
|
||||
* synchronization of bean creation. There is usually no need for internal
|
||||
* synchronization other than for purposes of lazy initialization within the
|
||||
|
||||
+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
|
||||
|
||||
+3
-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.
|
||||
@@ -1283,7 +1283,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
else {
|
||||
throw new NoSuchBeanDefinitionException(parentBeanName,
|
||||
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
|
||||
"': cannot be resolved without an AbstractBeanFactory parent");
|
||||
"': cannot be resolved without a ConfigurableBeanFactory parent");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1298,7 +1298,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
|
||||
// Set default singleton scope, if not configured before.
|
||||
if (!StringUtils.hasLength(mbd.getScope())) {
|
||||
mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
|
||||
mbd.setScope(SCOPE_SINGLETON);
|
||||
}
|
||||
|
||||
// A bean contained in a non-singleton bean cannot be a singleton itself.
|
||||
|
||||
+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.
|
||||
*/
|
||||
|
||||
+18
-2
@@ -162,6 +162,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
/** Map of bean definition objects, keyed by bean name. */
|
||||
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
|
||||
|
||||
/** Map from bean name to merged BeanDefinitionHolder. */
|
||||
private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);
|
||||
|
||||
/** Map of singleton and non-singleton bean names, keyed by dependency type. */
|
||||
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
|
||||
|
||||
@@ -759,8 +762,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
if (mbd.isFactoryMethodUnique && mbd.factoryMethodToIntrospect == null) {
|
||||
new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd);
|
||||
}
|
||||
return resolver.isAutowireCandidate(
|
||||
new BeanDefinitionHolder(mbd, beanName, getAliases(beanDefinitionName)), descriptor);
|
||||
BeanDefinitionHolder holder = (beanName.equals(beanDefinitionName) ?
|
||||
this.mergedBeanDefinitionHolders.computeIfAbsent(beanName,
|
||||
key -> new BeanDefinitionHolder(mbd, beanName, getAliases(beanDefinitionName))) :
|
||||
new BeanDefinitionHolder(mbd, beanName, getAliases(beanDefinitionName)));
|
||||
return resolver.isAutowireCandidate(holder, descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -783,9 +789,16 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
return iterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clearMergedBeanDefinition(String beanName) {
|
||||
super.clearMergedBeanDefinition(beanName);
|
||||
this.mergedBeanDefinitionHolders.remove(beanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearMetadataCache() {
|
||||
super.clearMetadataCache();
|
||||
this.mergedBeanDefinitionHolders.clear();
|
||||
clearByTypeCache();
|
||||
}
|
||||
|
||||
@@ -942,6 +955,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
if (existingDefinition != null || containsSingleton(beanName)) {
|
||||
resetBeanDefinition(beanName);
|
||||
}
|
||||
else if (isConfigurationFrozen()) {
|
||||
clearByTypeCache();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+13
-4
@@ -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.
|
||||
@@ -70,6 +70,10 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
|
||||
|
||||
/** Maximum number of suppressed exceptions to preserve. */
|
||||
private static final int SUPPRESSED_EXCEPTIONS_LIMIT = 100;
|
||||
|
||||
|
||||
/** Cache of singleton objects: bean name to bean instance. */
|
||||
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
|
||||
|
||||
@@ -90,7 +94,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
private final Set<String> inCreationCheckExclusions =
|
||||
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
|
||||
|
||||
/** List of suppressed Exceptions, available for associating related causes. */
|
||||
/** Collection of suppressed Exceptions, available for associating related causes. */
|
||||
@Nullable
|
||||
private Set<Exception> suppressedExceptions;
|
||||
|
||||
@@ -253,13 +257,17 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an Exception that happened to get suppressed during the creation of a
|
||||
* Register an exception that happened to get suppressed during the creation of a
|
||||
* singleton bean instance, e.g. a temporary circular reference resolution problem.
|
||||
* <p>The default implementation preserves any given exception in this registry's
|
||||
* collection of suppressed exceptions, up to a limit of 100 exceptions, adding
|
||||
* them as related causes to an eventual top-level {@link BeanCreationException}.
|
||||
* @param ex the Exception to register
|
||||
* @see BeanCreationException#getRelatedCauses()
|
||||
*/
|
||||
protected void onSuppressedException(Exception ex) {
|
||||
synchronized (this.singletonObjects) {
|
||||
if (this.suppressedExceptions != null) {
|
||||
if (this.suppressedExceptions != null && this.suppressedExceptions.size() < SUPPRESSED_EXCEPTIONS_LIMIT) {
|
||||
this.suppressedExceptions.add(ex);
|
||||
}
|
||||
}
|
||||
@@ -612,6 +620,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++) {
|
||||
|
||||
+33
@@ -1399,6 +1399,39 @@ public class DefaultListableBeanFactoryTests {
|
||||
lbf.getBean(TestBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeanByTypeWithLateRegistration() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
try {
|
||||
lbf.getBean(TestBean.class);
|
||||
fail("Should have thrown NoSuchBeanDefinitionException");
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// expected
|
||||
}
|
||||
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
|
||||
lbf.registerBeanDefinition("bd1", bd1);
|
||||
TestBean bean = lbf.getBean(TestBean.class);
|
||||
assertThat(bean.getBeanName(), equalTo("bd1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeanByTypeWithLateRegistrationAgainstFrozen() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
lbf.freezeConfiguration();
|
||||
try {
|
||||
lbf.getBean(TestBean.class);
|
||||
fail("Should have thrown NoSuchBeanDefinitionException");
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// expected
|
||||
}
|
||||
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
|
||||
lbf.registerBeanDefinition("bd1", bd1);
|
||||
TestBean bean = lbf.getBean(TestBean.class);
|
||||
assertThat(bean.getBeanName(), equalTo("bd1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeanByTypeDefinedInParent() {
|
||||
DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
|
||||
|
||||
@@ -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.19.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);
|
||||
}
|
||||
|
||||
@@ -18,17 +18,17 @@ dependencies {
|
||||
optional("javax.xml.ws:jaxws-api:2.3.1")
|
||||
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("org.apache-extras.beanshell:bsh:2.0b6")
|
||||
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)
|
||||
|
||||
+3
-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.
|
||||
@@ -33,7 +33,8 @@ import org.springframework.core.type.AnnotationMetadata;
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see EnableAspectJAutoProxy
|
||||
* @see org.springframework.cache.annotation.EnableCaching
|
||||
* @see org.springframework.transaction.annotation.EnableTransactionManagement
|
||||
*/
|
||||
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
|
||||
|
||||
+3
-5
@@ -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,7 +29,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
|
||||
import org.springframework.beans.factory.annotation.Lookup;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
@@ -386,8 +385,8 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
for (String type : types) {
|
||||
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
|
||||
if (isCandidateComponent(metadataReader)) {
|
||||
AnnotatedGenericBeanDefinition sbd = new AnnotatedGenericBeanDefinition(
|
||||
metadataReader.getAnnotationMetadata());
|
||||
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
|
||||
sbd.setSource(metadataReader.getResource());
|
||||
if (isCandidateComponent(sbd)) {
|
||||
if (debugEnabled) {
|
||||
logger.debug("Using candidate component class from index: " + type);
|
||||
@@ -430,7 +429,6 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
|
||||
if (isCandidateComponent(metadataReader)) {
|
||||
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
|
||||
sbd.setResource(resource);
|
||||
sbd.setSource(resource);
|
||||
if (isCandidateComponent(sbd)) {
|
||||
if (debugEnabled) {
|
||||
|
||||
+4
-4
@@ -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.
|
||||
@@ -344,9 +344,9 @@ import org.springframework.stereotype.Component;
|
||||
*
|
||||
* <p>By default, {@code @Bean} methods will be <em>eagerly instantiated</em> at container
|
||||
* bootstrap time. To avoid this, {@code @Configuration} may be used in conjunction with
|
||||
* the {@link Lazy @Lazy} annotation to indicate that all {@code @Bean} methods declared within
|
||||
* the class are by default lazily initialized. Note that {@code @Lazy} may be used on
|
||||
* individual {@code @Bean} methods as well.
|
||||
* the {@link Lazy @Lazy} annotation to indicate that all {@code @Bean} methods declared
|
||||
* within the class are by default lazily initialized. Note that {@code @Lazy} may be used
|
||||
* on individual {@code @Bean} methods as well.
|
||||
*
|
||||
* <h2>Testing support for {@code @Configuration} classes</h2>
|
||||
*
|
||||
|
||||
+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.
|
||||
@@ -209,7 +209,6 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
}
|
||||
|
||||
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
|
||||
beanDef.setResource(configClass.getResource());
|
||||
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
|
||||
|
||||
if (metadata.isStatic()) {
|
||||
@@ -381,6 +380,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
public ConfigurationClassBeanDefinition(ConfigurationClass configClass, MethodMetadata beanMethodMetadata) {
|
||||
this.annotationMetadata = configClass.getMetadata();
|
||||
this.factoryMethodMetadata = beanMethodMetadata;
|
||||
setResource(configClass.getResource());
|
||||
setLenientConstructorResolution(false);
|
||||
}
|
||||
|
||||
|
||||
+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";
|
||||
|
||||
+6
-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.
|
||||
@@ -170,8 +170,11 @@ import org.springframework.core.io.support.PropertySourceFactory;
|
||||
public @interface PropertySource {
|
||||
|
||||
/**
|
||||
* Indicate the name of this property source. If omitted, a name will
|
||||
* be generated based on the description of the underlying resource.
|
||||
* Indicate the name of this property source. If omitted, the {@link #factory()}
|
||||
* will generate a name based on the underlying resource (in the case of
|
||||
* {@link org.springframework.core.io.support.DefaultPropertySourceFactory}:
|
||||
* derived from the resource description through a corresponding name-less
|
||||
* {@link org.springframework.core.io.support.ResourcePropertySource} constructor).
|
||||
* @see org.springframework.core.env.PropertySource#getName()
|
||||
* @see org.springframework.core.io.Resource#getDescription()
|
||||
*/
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -60,6 +60,7 @@ public class ScannedGenericBeanDefinition extends GenericBeanDefinition implemen
|
||||
Assert.notNull(metadataReader, "MetadataReader must not be null");
|
||||
this.metadata = metadataReader.getAnnotationMetadata();
|
||||
setBeanClassName(this.metadata.getClassName());
|
||||
setResource(metadataReader.getResource());
|
||||
}
|
||||
|
||||
|
||||
|
||||
+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
|
||||
|
||||
}
|
||||
|
||||
+16
-14
@@ -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.
|
||||
@@ -57,6 +57,19 @@ public class CandidateComponentsIndex {
|
||||
this.index = parseIndex(content);
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, Entry> parseIndex(List<Properties> content) {
|
||||
MultiValueMap<String, Entry> index = new LinkedMultiValueMap<>();
|
||||
for (Properties entry : content) {
|
||||
entry.forEach((type, values) -> {
|
||||
String[] stereotypes = ((String) values).split(",");
|
||||
for (String stereotype : stereotypes) {
|
||||
index.add(stereotype, new Entry((String) type));
|
||||
}
|
||||
});
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the candidate types that are associated with the specified stereotype.
|
||||
@@ -76,21 +89,11 @@ public class CandidateComponentsIndex {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, Entry> parseIndex(List<Properties> content) {
|
||||
MultiValueMap<String, Entry> index = new LinkedMultiValueMap<>();
|
||||
for (Properties entry : content) {
|
||||
entry.forEach((type, values) -> {
|
||||
String[] stereotypes = ((String) values).split(",");
|
||||
for (String stereotype : stereotypes) {
|
||||
index.add(stereotype, new Entry((String) type));
|
||||
}
|
||||
});
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private static class Entry {
|
||||
|
||||
private final String type;
|
||||
|
||||
private final String packageName;
|
||||
|
||||
Entry(String type) {
|
||||
@@ -106,7 +109,6 @@ public class CandidateComponentsIndex {
|
||||
return this.type.startsWith(basePackage);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+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" });
|
||||
|
||||
+61
-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.
|
||||
@@ -28,16 +28,18 @@ import org.springframework.beans.BeanInstantiationException;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.support.StaticListableBeanFactory;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation2.NamedStubDao2;
|
||||
import org.springframework.context.index.CandidateComponentsTestClassLoader;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@@ -102,10 +104,66 @@ public class ClassPathBeanDefinitionScannerTests {
|
||||
@Test
|
||||
public void testDoubleScan() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
|
||||
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
|
||||
int beanCount = scanner.scan(BASE_PACKAGE);
|
||||
assertEquals(12, beanCount);
|
||||
scanner.scan(BASE_PACKAGE);
|
||||
|
||||
ClassPathBeanDefinitionScanner scanner2 = new ClassPathBeanDefinitionScanner(context) {
|
||||
@Override
|
||||
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
|
||||
super.postProcessBeanDefinition(beanDefinition, beanName);
|
||||
beanDefinition.setAttribute("someDifference", "someValue");
|
||||
}
|
||||
};
|
||||
scanner2.scan(BASE_PACKAGE);
|
||||
|
||||
assertTrue(context.containsBean("serviceInvocationCounter"));
|
||||
assertTrue(context.containsBean("fooServiceImpl"));
|
||||
assertTrue(context.containsBean("stubFooDao"));
|
||||
assertTrue(context.containsBean("myNamedComponent"));
|
||||
assertTrue(context.containsBean("myNamedDao"));
|
||||
assertTrue(context.containsBean("thoreau"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithIndex() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.setClassLoader(CandidateComponentsTestClassLoader.index(
|
||||
ClassPathScanningCandidateComponentProviderTests.class.getClassLoader(),
|
||||
new ClassPathResource("spring.components", FooServiceImpl.class)));
|
||||
|
||||
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
|
||||
int beanCount = scanner.scan(BASE_PACKAGE);
|
||||
assertEquals(12, beanCount);
|
||||
|
||||
assertTrue(context.containsBean("serviceInvocationCounter"));
|
||||
assertTrue(context.containsBean("fooServiceImpl"));
|
||||
assertTrue(context.containsBean("stubFooDao"));
|
||||
assertTrue(context.containsBean("myNamedComponent"));
|
||||
assertTrue(context.containsBean("myNamedDao"));
|
||||
assertTrue(context.containsBean("thoreau"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleScanWithIndex() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.setClassLoader(CandidateComponentsTestClassLoader.index(
|
||||
ClassPathScanningCandidateComponentProviderTests.class.getClassLoader(),
|
||||
new ClassPathResource("spring.components", FooServiceImpl.class)));
|
||||
|
||||
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
|
||||
int beanCount = scanner.scan(BASE_PACKAGE);
|
||||
assertEquals(12, beanCount);
|
||||
|
||||
ClassPathBeanDefinitionScanner scanner2 = new ClassPathBeanDefinitionScanner(context) {
|
||||
@Override
|
||||
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
|
||||
super.postProcessBeanDefinition(beanDefinition, beanName);
|
||||
beanDefinition.setAttribute("someDifference", "someValue");
|
||||
}
|
||||
};
|
||||
scanner2.scan(BASE_PACKAGE);
|
||||
|
||||
assertTrue(context.containsBean("serviceInvocationCounter"));
|
||||
assertTrue(context.containsBean("fooServiceImpl"));
|
||||
|
||||
+41
-39
@@ -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.
|
||||
@@ -40,8 +40,8 @@ import example.scannable.sub.BarComponent;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
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;
|
||||
@@ -80,18 +80,17 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
|
||||
provider.setResourceLoader(new DefaultResourceLoader(
|
||||
CandidateComponentsTestClassLoader.disableIndex(getClass().getClassLoader())));
|
||||
testDefault(provider, ScannedGenericBeanDefinition.class);
|
||||
testDefault(provider);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultsWithIndex() {
|
||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
|
||||
provider.setResourceLoader(new DefaultResourceLoader(TEST_BASE_CLASSLOADER));
|
||||
testDefault(provider, AnnotatedGenericBeanDefinition.class);
|
||||
testDefault(provider);
|
||||
}
|
||||
|
||||
private void testDefault(ClassPathScanningCandidateComponentProvider provider,
|
||||
Class<? extends BeanDefinition> expectedBeanDefinitionType) {
|
||||
private void testDefault(ClassPathScanningCandidateComponentProvider provider) {
|
||||
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
|
||||
assertTrue(containsBeanClass(candidates, DefaultNamedComponent.class));
|
||||
assertTrue(containsBeanClass(candidates, NamedComponent.class));
|
||||
@@ -101,7 +100,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
assertTrue(containsBeanClass(candidates, ServiceInvocationCounter.class));
|
||||
assertTrue(containsBeanClass(candidates, BarComponent.class));
|
||||
assertEquals(7, candidates.size());
|
||||
assertBeanDefinitionType(candidates, expectedBeanDefinitionType);
|
||||
assertBeanDefinitionType(candidates);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -109,22 +108,21 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
|
||||
provider.setResourceLoader(new DefaultResourceLoader(
|
||||
CandidateComponentsTestClassLoader.disableIndex(getClass().getClassLoader())));
|
||||
testAntStyle(provider, ScannedGenericBeanDefinition.class);
|
||||
testAntStyle(provider);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void antStylePackageWithIndex() {
|
||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
|
||||
provider.setResourceLoader(new DefaultResourceLoader(TEST_BASE_CLASSLOADER));
|
||||
testAntStyle(provider, AnnotatedGenericBeanDefinition.class);
|
||||
testAntStyle(provider);
|
||||
}
|
||||
|
||||
private void testAntStyle(ClassPathScanningCandidateComponentProvider provider,
|
||||
Class<? extends BeanDefinition> expectedBeanDefinitionType) {
|
||||
private void testAntStyle(ClassPathScanningCandidateComponentProvider provider) {
|
||||
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE + ".**.sub");
|
||||
assertTrue(containsBeanClass(candidates, BarComponent.class));
|
||||
assertEquals(1, candidates.size());
|
||||
assertBeanDefinitionType(candidates, expectedBeanDefinitionType);
|
||||
assertBeanDefinitionType(candidates);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -151,7 +149,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
provider.addIncludeFilter(new AnnotationTypeFilter(Component.class));
|
||||
provider.resetFilters(true);
|
||||
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
|
||||
assertBeanDefinitionType(candidates, AnnotatedGenericBeanDefinition.class);
|
||||
assertBeanDefinitionType(candidates);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -159,20 +157,19 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
|
||||
provider.setResourceLoader(new DefaultResourceLoader(
|
||||
CandidateComponentsTestClassLoader.disableIndex(getClass().getClassLoader())));
|
||||
testCustomAnnotationTypeIncludeFilter(provider, ScannedGenericBeanDefinition.class);
|
||||
testCustomAnnotationTypeIncludeFilter(provider);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customAnnotationTypeIncludeFilterWithIndex() {
|
||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
|
||||
provider.setResourceLoader(new DefaultResourceLoader(TEST_BASE_CLASSLOADER));
|
||||
testCustomAnnotationTypeIncludeFilter(provider, AnnotatedGenericBeanDefinition.class);
|
||||
testCustomAnnotationTypeIncludeFilter(provider);
|
||||
}
|
||||
|
||||
private void testCustomAnnotationTypeIncludeFilter(ClassPathScanningCandidateComponentProvider provider,
|
||||
Class<? extends BeanDefinition> expectedBeanDefinitionType) {
|
||||
private void testCustomAnnotationTypeIncludeFilter(ClassPathScanningCandidateComponentProvider provider) {
|
||||
provider.addIncludeFilter(new AnnotationTypeFilter(Component.class));
|
||||
testDefault(provider, expectedBeanDefinitionType);
|
||||
testDefault(provider);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -180,18 +177,17 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
|
||||
provider.setResourceLoader(new DefaultResourceLoader(
|
||||
CandidateComponentsTestClassLoader.disableIndex(getClass().getClassLoader())));
|
||||
testCustomAssignableTypeIncludeFilter(provider, ScannedGenericBeanDefinition.class);
|
||||
testCustomAssignableTypeIncludeFilter(provider);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customAssignableTypeIncludeFilterWithIndex() {
|
||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
|
||||
provider.setResourceLoader(new DefaultResourceLoader(TEST_BASE_CLASSLOADER));
|
||||
testCustomAssignableTypeIncludeFilter(provider, AnnotatedGenericBeanDefinition.class);
|
||||
testCustomAssignableTypeIncludeFilter(provider);
|
||||
}
|
||||
|
||||
private void testCustomAssignableTypeIncludeFilter(ClassPathScanningCandidateComponentProvider provider,
|
||||
Class<? extends BeanDefinition> expectedBeanDefinitionType) {
|
||||
private void testCustomAssignableTypeIncludeFilter(ClassPathScanningCandidateComponentProvider provider) {
|
||||
provider.addIncludeFilter(new AssignableTypeFilter(FooService.class));
|
||||
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
|
||||
// Interfaces/Abstract class are filtered out automatically.
|
||||
@@ -199,7 +195,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
assertTrue(containsBeanClass(candidates, FooServiceImpl.class));
|
||||
assertTrue(containsBeanClass(candidates, ScopedProxyTestBean.class));
|
||||
assertEquals(3, candidates.size());
|
||||
assertBeanDefinitionType(candidates, expectedBeanDefinitionType);
|
||||
assertBeanDefinitionType(candidates);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -207,18 +203,17 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
|
||||
provider.setResourceLoader(new DefaultResourceLoader(
|
||||
CandidateComponentsTestClassLoader.disableIndex(getClass().getClassLoader())));
|
||||
testCustomSupportedIncludeAndExcludeFilter(provider, ScannedGenericBeanDefinition.class);
|
||||
testCustomSupportedIncludeAndExcludeFilter(provider);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customSupportedIncludeAndExcludeFilterWithIndex() {
|
||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
|
||||
provider.setResourceLoader(new DefaultResourceLoader(TEST_BASE_CLASSLOADER));
|
||||
testCustomSupportedIncludeAndExcludeFilter(provider, AnnotatedGenericBeanDefinition.class);
|
||||
testCustomSupportedIncludeAndExcludeFilter(provider);
|
||||
}
|
||||
|
||||
private void testCustomSupportedIncludeAndExcludeFilter(ClassPathScanningCandidateComponentProvider provider,
|
||||
Class<? extends BeanDefinition> expectedBeanDefinitionType) {
|
||||
private void testCustomSupportedIncludeAndExcludeFilter(ClassPathScanningCandidateComponentProvider provider) {
|
||||
provider.addIncludeFilter(new AnnotationTypeFilter(Component.class));
|
||||
provider.addExcludeFilter(new AnnotationTypeFilter(Service.class));
|
||||
provider.addExcludeFilter(new AnnotationTypeFilter(Repository.class));
|
||||
@@ -227,7 +222,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
assertTrue(containsBeanClass(candidates, ServiceInvocationCounter.class));
|
||||
assertTrue(containsBeanClass(candidates, BarComponent.class));
|
||||
assertEquals(3, candidates.size());
|
||||
assertBeanDefinitionType(candidates, expectedBeanDefinitionType);
|
||||
assertBeanDefinitionType(candidates);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -240,7 +235,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
|
||||
assertTrue(containsBeanClass(candidates, DefaultNamedComponent.class));
|
||||
assertEquals(1, candidates.size());
|
||||
assertBeanDefinitionType(candidates, ScannedGenericBeanDefinition.class);
|
||||
assertBeanDefinitionType(candidates);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -251,7 +246,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
|
||||
assertTrue(containsBeanClass(candidates, StubFooDao.class));
|
||||
assertEquals(1, candidates.size());
|
||||
assertBeanDefinitionType(candidates, ScannedGenericBeanDefinition.class);
|
||||
assertBeanDefinitionType(candidates);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -260,7 +255,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
provider.setResourceLoader(new DefaultResourceLoader(
|
||||
CandidateComponentsTestClassLoader.disableIndex(getClass().getClassLoader())));
|
||||
provider.addExcludeFilter(new RegexPatternTypeFilter(Pattern.compile(TEST_BASE_PACKAGE + ".*Named.*")));
|
||||
testExclude(provider, ScannedGenericBeanDefinition.class);
|
||||
testExclude(provider);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -268,18 +263,17 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
|
||||
provider.setResourceLoader(new DefaultResourceLoader(TEST_BASE_CLASSLOADER));
|
||||
provider.addExcludeFilter(new RegexPatternTypeFilter(Pattern.compile(TEST_BASE_PACKAGE + ".*Named.*")));
|
||||
testExclude(provider, AnnotatedGenericBeanDefinition.class);
|
||||
testExclude(provider);
|
||||
}
|
||||
|
||||
private void testExclude(ClassPathScanningCandidateComponentProvider provider,
|
||||
Class<? extends BeanDefinition> expectedBeanDefinitionType) {
|
||||
private void testExclude(ClassPathScanningCandidateComponentProvider provider) {
|
||||
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
|
||||
assertTrue(containsBeanClass(candidates, FooServiceImpl.class));
|
||||
assertTrue(containsBeanClass(candidates, StubFooDao.class));
|
||||
assertTrue(containsBeanClass(candidates, ServiceInvocationCounter.class));
|
||||
assertTrue(containsBeanClass(candidates, BarComponent.class));
|
||||
assertEquals(4, candidates.size());
|
||||
assertBeanDefinitionType(candidates, expectedBeanDefinitionType);
|
||||
assertBeanDefinitionType(candidates);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -307,7 +301,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithAspectAnnotationOnly() throws Exception {
|
||||
public void testWithAspectAnnotationOnly() {
|
||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
|
||||
provider.addIncludeFilter(new AnnotationTypeFilter(Aspect.class));
|
||||
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
|
||||
@@ -501,6 +495,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())) {
|
||||
@@ -510,10 +513,9 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void assertBeanDefinitionType(Set<BeanDefinition> candidates,
|
||||
Class<? extends BeanDefinition> expectedType) {
|
||||
private void assertBeanDefinitionType(Set<BeanDefinition> candidates) {
|
||||
candidates.forEach(c -> {
|
||||
assertThat(c, is(instanceOf(expectedType)));
|
||||
assertThat(c, is(instanceOf(ScannedGenericBeanDefinition.class)));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+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);
|
||||
}
|
||||
|
||||
+2
-2
@@ -92,7 +92,7 @@ public class CandidateComponentsIndexLoaderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadIndexNoEntry() throws IOException {
|
||||
public void loadIndexNoEntry() {
|
||||
CandidateComponentsIndex index = CandidateComponentsIndexLoader.loadIndex(
|
||||
CandidateComponentsTestClassLoader.index(getClass().getClassLoader(),
|
||||
new ClassPathResource("empty-spring.components", getClass())));
|
||||
@@ -100,7 +100,7 @@ public class CandidateComponentsIndexLoaderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadIndexWithException() throws IOException {
|
||||
public void loadIndexWithException() {
|
||||
final IOException cause = new IOException("test exception");
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("Unable to load indexes");
|
||||
|
||||
+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) {
|
||||
|
||||
@@ -259,6 +259,9 @@ public class Enhancer extends AbstractClassGenerator {
|
||||
public void setSuperclass(Class superclass) {
|
||||
if (superclass != null && superclass.isInterface()) {
|
||||
setInterfaces(new Class[]{superclass});
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(superclass);
|
||||
// SPRING PATCH END
|
||||
}
|
||||
else if (superclass != null && superclass.equals(Object.class)) {
|
||||
// affects choice of ClassLoader
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -18,9 +18,6 @@ package org.springframework.core;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -34,8 +31,6 @@ import org.springframework.util.ClassUtils;
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract class KotlinDetector {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(KotlinDetector.class);
|
||||
|
||||
@Nullable
|
||||
private static final Class<? extends Annotation> kotlinMetadata;
|
||||
|
||||
@@ -53,9 +48,6 @@ public abstract class KotlinDetector {
|
||||
}
|
||||
kotlinMetadata = (Class<? extends Annotation>) metadata;
|
||||
kotlinReflectPresent = ClassUtils.isPresent("kotlin.reflect.full.KClasses", classLoader);
|
||||
if (kotlinMetadata != null && !kotlinReflectPresent) {
|
||||
logger.info("Kotlin reflection implementation not found at runtime, related features won't be available.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
-1
@@ -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.
|
||||
@@ -33,6 +33,8 @@ public interface PropertySourceFactory {
|
||||
/**
|
||||
* Create a {@link PropertySource} that wraps the given resource.
|
||||
* @param name the name of the property source
|
||||
* (can be {@code null} in which case the factory implementation
|
||||
* will have to generate a name based on the given resource)
|
||||
* @param resource the resource (potentially encoded) to wrap
|
||||
* @return the new {@link PropertySource} (never {@code null})
|
||||
* @throws IOException if resource resolution failed
|
||||
|
||||
+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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -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);
|
||||
@@ -527,7 +532,7 @@ public abstract class ClassUtils {
|
||||
* @param lhsType the target type
|
||||
* @param rhsType the value type that should be assigned to the target type
|
||||
* @return if the target type is assignable from the value type
|
||||
* @see TypeUtils#isAssignable
|
||||
* @see TypeUtils#isAssignable(java.lang.reflect.Type, java.lang.reflect.Type)
|
||||
*/
|
||||
public static boolean isAssignable(Class<?> lhsType, Class<?> rhsType) {
|
||||
Assert.notNull(lhsType, "Left-hand side type must not be null");
|
||||
@@ -537,17 +542,12 @@ public abstract class ClassUtils {
|
||||
}
|
||||
if (lhsType.isPrimitive()) {
|
||||
Class<?> resolvedPrimitive = primitiveWrapperTypeMap.get(rhsType);
|
||||
if (lhsType == resolvedPrimitive) {
|
||||
return true;
|
||||
}
|
||||
return (lhsType == resolvedPrimitive);
|
||||
}
|
||||
else {
|
||||
Class<?> resolvedWrapper = primitiveTypeToWrapperMap.get(rhsType);
|
||||
if (resolvedWrapper != null && lhsType.isAssignableFrom(resolvedWrapper)) {
|
||||
return true;
|
||||
}
|
||||
return (resolvedWrapper != null && lhsType.isAssignableFrom(resolvedWrapper));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1059,7 +1059,7 @@ public abstract class ClassUtils {
|
||||
* @param clazz the clazz to analyze
|
||||
* @param paramTypes the parameter types of the method
|
||||
* @return whether the class has a corresponding constructor
|
||||
* @see Class#getMethod
|
||||
* @see Class#getConstructor
|
||||
*/
|
||||
public static boolean hasConstructor(Class<?> clazz, Class<?>... paramTypes) {
|
||||
return (getConstructorIfAvailable(clazz, paramTypes) != null);
|
||||
@@ -1291,13 +1291,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 +1308,8 @@ public abstract class ClassUtils {
|
||||
}
|
||||
current = current.getSuperclass();
|
||||
}
|
||||
}
|
||||
return method;
|
||||
return key;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
@@ -24,9 +24,12 @@ import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import static java.nio.file.FileVisitOption.FOLLOW_LINKS;
|
||||
|
||||
/**
|
||||
* Utility methods for working with the file system.
|
||||
*
|
||||
@@ -65,11 +68,11 @@ public abstract class FileSystemUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the supplied {@link File} - for directories,
|
||||
* Delete the supplied {@link File} — for directories,
|
||||
* recursively delete any nested directories or files as well.
|
||||
* @param root the root {@code File} to delete
|
||||
* @return {@code true} if the {@code File} existed and was deleted,
|
||||
* or {@code false} it it did not exist
|
||||
* or {@code false} if it did not exist
|
||||
* @throws IOException in the case of I/O errors
|
||||
* @since 5.0
|
||||
*/
|
||||
@@ -123,7 +126,7 @@ public abstract class FileSystemUtils {
|
||||
BasicFileAttributes srcAttr = Files.readAttributes(src, BasicFileAttributes.class);
|
||||
|
||||
if (srcAttr.isDirectory()) {
|
||||
Files.walkFileTree(src, new SimpleFileVisitor<Path>() {
|
||||
Files.walkFileTree(src, EnumSet.of(FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
||||
Files.createDirectories(dest.resolve(src.relativize(dir)));
|
||||
|
||||
@@ -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;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user