mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
86 Commits
5.2.x
...
v4.0.4.RELEASE
| Author | SHA1 | Date | |
|---|---|---|---|
| 44ae54f252 | |||
| 8f175046c8 | |||
| c1dbd9f150 | |||
| 42a35ef3be | |||
| 21fd68150a | |||
| d20259be1d | |||
| 6ca921021c | |||
| eab9d24c31 | |||
| 15749c2a9d | |||
| 93b0f0b126 | |||
| 27b2ed1614 | |||
| 790d62bcb1 | |||
| 563476f57c | |||
| 79de45b805 | |||
| 63a868dafb | |||
| 1afdd9bd75 | |||
| d0c839f0eb | |||
| 744727b8aa | |||
| 9fbb7394e2 | |||
| 80cb0c4e5b | |||
| 5c4804f4a4 | |||
| a679f3e7a3 | |||
| bd5b3749c5 | |||
| 89398b0811 | |||
| a87c9b8c5c | |||
| d0f9853769 | |||
| bed739ce92 | |||
| cb712afa97 | |||
| c97c246940 | |||
| 4196e6c96f | |||
| 59cef3ce81 | |||
| c8ea80d7ed | |||
| 656fc52ff9 | |||
| a4d6f8473e | |||
| 443fb8e4ee | |||
| 95b1cb7173 | |||
| 51fb485181 | |||
| f16e6c4105 | |||
| 4dbc0c296c | |||
| d71d38bfaf | |||
| eb28259371 | |||
| 7ae6a60f43 | |||
| d3c9a31e9a | |||
| 5aa126600f | |||
| 2f15f72fcc | |||
| d5aacdefd9 | |||
| e379e77b96 | |||
| 9c45755890 | |||
| 5962fc2590 | |||
| 1b59b4eb26 | |||
| f6b89c2ca9 | |||
| 82c32db5a1 | |||
| 52f580149f | |||
| 271fe4f554 | |||
| 02e8198283 | |||
| 090ab4bb6d | |||
| 18ef1d4f76 | |||
| d9cb44527c | |||
| 8e44521ec4 | |||
| d28c6d8bdb | |||
| c9432ce499 | |||
| 2d8e0c8f87 | |||
| 03ae8eeb95 | |||
| 9230b38aea | |||
| d5ce30f360 | |||
| 428aee5b72 | |||
| f7a17added | |||
| 196f629a20 | |||
| 7135e729e2 | |||
| 21874627d2 | |||
| 3ab88b857b | |||
| 294545d07a | |||
| 38cd79047a | |||
| 8a779c32d5 | |||
| 7ba31dee45 | |||
| 1c45d7573c | |||
| f014bbb5cf | |||
| d1030b798d | |||
| d628025f13 | |||
| 30ea1a3475 | |||
| 7b014eaa55 | |||
| e21c47d4ce | |||
| 632ae6a4df | |||
| 989f6194b6 | |||
| 17bf5b991f | |||
| cd9d7cfe4f |
+38
-35
@@ -3,7 +3,7 @@ buildscript {
|
||||
maven { url "http://repo.springsource.org/plugins-release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.5")
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.6")
|
||||
classpath("org.asciidoctor:asciidoctor-gradle-plugin:0.7.0")
|
||||
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.8")
|
||||
}
|
||||
@@ -16,18 +16,19 @@ configure(allprojects) { project ->
|
||||
ext.aspectjVersion = "1.7.4"
|
||||
ext.groovyVersion = "1.8.9"
|
||||
ext.hibernate3Version = "3.6.10.Final"
|
||||
ext.hibernate4Version = "4.2.11.Final"
|
||||
ext.hibernate4Version = "4.2.12.Final"
|
||||
ext.hibValVersion = "4.3.1.Final"
|
||||
ext.hsqldbVersion = "2.3.2"
|
||||
ext.jackson1Version = "1.9.13"
|
||||
ext.jackson2Version = "2.3.1"
|
||||
ext.jackson2Version = "2.3.3"
|
||||
ext.jasperReportsVersion = "5.5.1"
|
||||
ext.jettyVersion = "9.1.3.v20140225"
|
||||
ext.jettyVersion = "9.1.4.v20140401"
|
||||
ext.jodaVersion = "2.3"
|
||||
ext.junitVersion = "4.11"
|
||||
ext.slf4jVersion = "1.7.6"
|
||||
ext.slf4jVersion = "1.7.7"
|
||||
ext.tiles2Version = "2.2.2"
|
||||
ext.tiles3Version = "3.0.3"
|
||||
ext.tomcatVersion = "8.0.5"
|
||||
ext.xstreamVersion = "1.4.7"
|
||||
|
||||
ext.gradleScriptDir = "${rootProject.projectDir}/gradle"
|
||||
@@ -71,14 +72,12 @@ configure(allprojects) { project ->
|
||||
include(["**/*Tests.class", "**/*Test.class"])
|
||||
// Since we set scanForTestClasses to false, we need to filter out inner
|
||||
// classes with the "$" pattern; otherwise, using -Dtest.single=MyTests to
|
||||
// run MyTests by itself will fail if MyTests contains any inner classes.
|
||||
// run MyTests by itself will fail if MyTests contains any inner classes.
|
||||
exclude(["**/Abstract*.class", '**/*$*'])
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url "http://repo.spring.io/libs-release" }
|
||||
maven { url "http://repo.spring.io/milestone" } // for AspectJ 1.8.0.M1
|
||||
maven { url "https://oss.sonatype.org/content/repositories/releases" } // javax.cache
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -93,7 +92,7 @@ configure(allprojects) { project ->
|
||||
|
||||
ext.javadocLinks = [
|
||||
"http://docs.oracle.com/javase/7/docs/api/",
|
||||
"http://docs.oracle.com/javaee/6/api/",
|
||||
"http://docs.oracle.com/javaee/7/api/",
|
||||
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ
|
||||
"http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
|
||||
"http://glassfish.java.net/nonav/docs/v3/api/",
|
||||
@@ -376,7 +375,7 @@ project("spring-context") {
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("org.beanshell:bsh:2.0b4")
|
||||
optional("org.jruby:jruby:1.7.10")
|
||||
optional("org.jruby:jruby:1.7.12")
|
||||
testCompile("javax.inject:javax.inject-tck:1")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.4")
|
||||
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
@@ -397,7 +396,8 @@ project("spring-messaging") {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-context"))
|
||||
optional("org.projectreactor:reactor-core:1.0.1.RELEASE")
|
||||
optional("org.projectreactor:reactor-core:1.1.0.RELEASE")
|
||||
optional("org.projectreactor:reactor-net:1.1.0.RELEASE")
|
||||
optional("org.projectreactor:reactor-tcp:1.0.1.RELEASE")
|
||||
optional("org.eclipse.jetty.websocket:websocket-server:${jettyVersion}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet-api"
|
||||
@@ -417,9 +417,9 @@ project("spring-messaging") {
|
||||
testCompile("org.eclipse.jetty:jetty-webapp:${jettyVersion}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet-api"
|
||||
}
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:8.0.3")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:8.0.3")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:8.0.3")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:${tomcatVersion}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.4")
|
||||
testCompile("log4j:log4j:1.2.17")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
@@ -458,8 +458,9 @@ project("spring-oxm") {
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
optional("org.codehaus.castor:castor-xml:1.3.2") {
|
||||
optional("org.codehaus.castor:castor-xml:1.3.3") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
exclude group: "org.springframework", module: "spring-context"
|
||||
}
|
||||
optional("org.apache.xmlbeans:xmlbeans:2.6.0") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
@@ -509,11 +510,11 @@ project("spring-jdbc") {
|
||||
compile(project(":spring-tx"))
|
||||
optional(project(":spring-context")) // for JndiDataSourceLookup
|
||||
optional("javax.transaction:javax.transaction-api:1.2")
|
||||
optional("c3p0:c3p0:0.9.1.2")
|
||||
optional("com.mchange:c3p0:0.9.2.1")
|
||||
optional("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
optional("com.h2database:h2:1.0.71")
|
||||
optional("org.apache.derby:derby:10.10.1.1")
|
||||
optional("org.apache.derby:derbyclient:10.10.1.1")
|
||||
optional("com.h2database:h2:1.3.176")
|
||||
optional("org.apache.derby:derby:10.10.2.0")
|
||||
optional("org.apache.derby:derbyclient:10.10.2.0")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,8 +528,8 @@ project("spring-context-support") {
|
||||
optional(project(":spring-jdbc")) // for Quartz support
|
||||
optional(project(":spring-tx")) // for Quartz support
|
||||
optional("javax.mail:mail:1.4.7")
|
||||
optional("javax.cache:cache-api:1.0.0-RC1")
|
||||
optional("com.google.guava:guava:16.0.1")
|
||||
optional("javax.cache:cache-api:1.0.0")
|
||||
optional("com.google.guava:guava:17.0")
|
||||
optional("net.sf.ehcache:ehcache-core:2.6.5")
|
||||
optional("org.quartz-scheduler:quartz:1.8.6") {
|
||||
exclude group: "org.slf4j", module: "slf4j-log4j12"
|
||||
@@ -538,7 +539,7 @@ project("spring-context-support") {
|
||||
optional("org.freemarker:freemarker:2.3.20")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("net.sf.jasperreports:jasperreports:$jasperReportsVersion")
|
||||
testCompile("org.apache.poi:poi:3.9")
|
||||
testCompile("org.apache.poi:poi:3.10-FINAL")
|
||||
testCompile("commons-beanutils:commons-beanutils:1.8.0") // for Velocity/JasperReports
|
||||
testCompile("commons-digester:commons-digester:1.8.1") // for Velocity/JasperReports
|
||||
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
@@ -599,7 +600,7 @@ project("spring-websocket") {
|
||||
optional(project(":spring-webmvc"))
|
||||
optional("javax.servlet:javax.servlet-api:3.1.0")
|
||||
optional("javax.websocket:javax.websocket-api:1.0")
|
||||
optional("org.apache.tomcat:tomcat-websocket:8.0.3") {
|
||||
optional("org.apache.tomcat:tomcat-websocket:${tomcatVersion}") {
|
||||
exclude group: "org.apache.tomcat", module: "tomcat-websocket-api"
|
||||
exclude group: "org.apache.tomcat", module: "tomcat-servlet-api"
|
||||
}
|
||||
@@ -612,20 +613,20 @@ project("spring-websocket") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet"
|
||||
}
|
||||
optional("org.eclipse.jetty.websocket:websocket-client:${jettyVersion}")
|
||||
optional("io.undertow:undertow-core:1.0.0.Final")
|
||||
optional("io.undertow:undertow-servlet:1.0.0.Final") {
|
||||
optional("io.undertow:undertow-core:1.0.1.Final")
|
||||
optional("io.undertow:undertow-servlet:1.0.1.Final") {
|
||||
exclude group: "org.jboss.spec.javax.servlet", module: "jboss-servlet-api_3.1_spec"
|
||||
exclude group: "org.jboss.spec.javax.annotation", module: "jboss-annotations-api_1.2_spec"
|
||||
}
|
||||
optional("io.undertow:undertow-websockets-jsr:1.0.0.Final") {
|
||||
optional("io.undertow:undertow-websockets-jsr:1.0.1.Final") {
|
||||
exclude group: "org.jboss.spec.javax.websocket", module: "jboss-websocket-api_1.0_spec"
|
||||
}
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:8.0.3")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:8.0.3")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:8.0.3")
|
||||
testCompile("org.projectreactor:reactor-core:1.0.1.RELEASE")
|
||||
testCompile("org.projectreactor:reactor-tcp:1.0.1.RELEASE")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:${tomcatVersion}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}")
|
||||
testCompile("org.projectreactor:reactor-core:1.1.0.RELEASE")
|
||||
testCompile("org.projectreactor:reactor-net:1.1.0.RELEASE")
|
||||
testCompile("log4j:log4j:1.2.17")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
@@ -682,6 +683,7 @@ project("spring-orm-hibernate4") {
|
||||
optional("org.hibernate:hibernate-core:${hibernate4Version}")
|
||||
optional("org.hibernate:hibernate-entitymanager:${hibernate4Version}")
|
||||
optional("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -701,7 +703,7 @@ project("spring-webmvc") {
|
||||
optional("javax.servlet.jsp:jsp-api:2.2")
|
||||
optional("javax.servlet:jstl:1.2")
|
||||
optional("net.sourceforge.jexcelapi:jxl:2.6.12")
|
||||
optional("org.apache.poi:poi:3.9")
|
||||
optional("org.apache.poi:poi:3.10-FINAL")
|
||||
optional("org.apache.velocity:velocity:1.7")
|
||||
optional("velocity-tools:velocity-tools-view:1.4")
|
||||
optional("org.freemarker:freemarker:2.3.20")
|
||||
@@ -863,6 +865,7 @@ project("spring-test") {
|
||||
|
||||
task testNG(type: Test) {
|
||||
useTestNG()
|
||||
scanForTestClasses = false
|
||||
include(["**/testng/**/*Tests.class", "**/testng/**/*Test.class"])
|
||||
// Show STD_OUT & STD_ERR of the test JVM(s) on the console:
|
||||
// testLogging.showStandardStreams = true
|
||||
@@ -889,8 +892,8 @@ project("spring-aspects") {
|
||||
|
||||
dependencies {
|
||||
aspects(project(":spring-orm"))
|
||||
ajc("org.aspectj:aspectjtools:1.8.0.RC2") // needed for ajc on JDK 8 only
|
||||
rt("org.aspectj:aspectjrt:1.8.0.RC2") // needed for ajc on JDK 8 only
|
||||
ajc("org.aspectj:aspectjtools:1.8.0") // needed for ajc on JDK 8 only
|
||||
rt("org.aspectj:aspectjrt:1.8.0") // needed for ajc on JDK 8 only
|
||||
compile("org.aspectj:aspectjweaver:${aspectjVersion}") // exposing regular AspectJ version to users
|
||||
provided("org.eclipse.persistence:javax.persistence:2.0.0")
|
||||
optional(project(":spring-aop")) // for @Async support
|
||||
@@ -1175,7 +1178,7 @@ configure(rootProject) {
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
description = "Generates gradlew[.bat] scripts"
|
||||
gradleVersion = "1.11"
|
||||
gradleVersion = "1.12"
|
||||
|
||||
doLast() {
|
||||
def gradleOpts = "-XX:MaxMetaspaceSize=1024m -Xmx1024m"
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
version=4.0.4.BUILD-SNAPSHOT
|
||||
version=4.0.4.RELEASE
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+2
-2
@@ -1,6 +1,6 @@
|
||||
#Wed Feb 12 23:28:21 CET 2014
|
||||
#Wed Apr 30 13:06:57 CEST 2014
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-bin.zip
|
||||
|
||||
+59
-54
@@ -29,7 +29,6 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.aspectj.weaver.BCException;
|
||||
import org.aspectj.weaver.patterns.NamePattern;
|
||||
import org.aspectj.weaver.reflect.ReflectionWorld;
|
||||
import org.aspectj.weaver.reflect.ReflectionWorld.ReflectionWorldException;
|
||||
import org.aspectj.weaver.reflect.ShadowMatchImpl;
|
||||
import org.aspectj.weaver.tools.ContextBasedMatcher;
|
||||
@@ -108,6 +107,8 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private transient ClassLoader pointcutClassLoader;
|
||||
|
||||
private transient PointcutExpression pointcutExpression;
|
||||
|
||||
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||
@@ -185,20 +186,13 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
throw new IllegalStateException("Must set property 'expression' before attempting to match");
|
||||
}
|
||||
if (this.pointcutExpression == null) {
|
||||
this.pointcutExpression = buildPointcutExpression();
|
||||
this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
private PointcutExpression buildPointcutExpression() {
|
||||
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
return buildPointcutExpression(cl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
@@ -252,23 +246,22 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
public boolean matches(Class<?> targetClass) {
|
||||
checkReadyToMatch();
|
||||
try {
|
||||
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
|
||||
}
|
||||
catch (ReflectionWorldException rwe) {
|
||||
logger.debug("PointcutExpression matching rejected target class", rwe);
|
||||
try {
|
||||
// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
|
||||
return getFallbackPointcutExpression(targetClass).couldMatchJoinPointsInType(targetClass);
|
||||
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
|
||||
}
|
||||
catch (BCException bce) {
|
||||
logger.debug("Fallback PointcutExpression matching rejected target class", bce);
|
||||
return false;
|
||||
catch (ReflectionWorldException ex) {
|
||||
logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
|
||||
// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
|
||||
PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
|
||||
if (fallbackExpression != null) {
|
||||
return fallbackExpression.couldMatchJoinPointsInType(targetClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (BCException ex) {
|
||||
logger.debug("PointcutExpression matching rejected target class", ex);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -365,12 +358,19 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
|
||||
/**
|
||||
* Get a new pointcut expression based on a target class's loader, rather
|
||||
* than the default.
|
||||
* Get a new pointcut expression based on a target class's loader rather than the default.
|
||||
*/
|
||||
private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) {
|
||||
ClassLoader classLoader = targetClass.getClassLoader();
|
||||
return (classLoader != null ? buildPointcutExpression(classLoader) : this.pointcutExpression);
|
||||
try {
|
||||
ClassLoader classLoader = targetClass.getClassLoader();
|
||||
if (classLoader != null && classLoader != this.pointcutClassLoader) {
|
||||
return buildPointcutExpression(classLoader);
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Failed to create fallback PointcutExpression", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
|
||||
@@ -396,46 +396,51 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
if (shadowMatch == null) {
|
||||
synchronized (this.shadowMatchCache) {
|
||||
// Not found - now check again with full lock...
|
||||
PointcutExpression fallbackExpression = null;
|
||||
Method methodToMatch = targetMethod;
|
||||
PointcutExpression fallbackPointcutExpression = null;
|
||||
shadowMatch = this.shadowMatchCache.get(methodToMatch);
|
||||
shadowMatch = this.shadowMatchCache.get(targetMethod);
|
||||
if (shadowMatch == null) {
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(targetMethod);
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex) {
|
||||
catch (ReflectionWorldException ex) {
|
||||
// Failed to introspect target method, probably because it has been loaded
|
||||
// in a special ClassLoader. Let's try the original method instead...
|
||||
// in a special ClassLoader. Let's try the declaring ClassLoader instead...
|
||||
try {
|
||||
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex2) {
|
||||
if (targetMethod == originalMethod) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
if (fallbackExpression != null) {
|
||||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(originalMethod);
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex3) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's simply consider this method as non-matching.
|
||||
methodToMatch = originalMethod;
|
||||
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
try {
|
||||
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex4) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
}
|
||||
}
|
||||
catch (ReflectionWorldException ex2) {
|
||||
fallbackExpression = null;
|
||||
}
|
||||
}
|
||||
if (shadowMatch == null && targetMethod != originalMethod) {
|
||||
methodToMatch = originalMethod;
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorldException ex3) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's try the original method's declaring class before we give up...
|
||||
try {
|
||||
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
if (fallbackExpression != null) {
|
||||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
}
|
||||
catch (ReflectionWorldException ex4) {
|
||||
fallbackExpression = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shadowMatch.maybeMatches() && fallbackPointcutExpression != null) {
|
||||
if (shadowMatch == null) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
}
|
||||
else if (shadowMatch.maybeMatches() && fallbackExpression != null) {
|
||||
shadowMatch = new DefensiveShadowMatch(shadowMatch,
|
||||
fallbackPointcutExpression.matchesMethodExecution(methodToMatch));
|
||||
fallbackExpression.matchesMethodExecution(methodToMatch));
|
||||
}
|
||||
this.shadowMatchCache.put(targetMethod, shadowMatch);
|
||||
}
|
||||
|
||||
+35
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -91,9 +91,11 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
|
||||
// Ignore AOP infrastructure such as scoped proxies.
|
||||
return bean;
|
||||
}
|
||||
if (isEligible(bean, beanName)) {
|
||||
if (bean instanceof Advised) {
|
||||
Advised advised = (Advised) bean;
|
||||
|
||||
if (bean instanceof Advised) {
|
||||
Advised advised = (Advised) bean;
|
||||
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
|
||||
// Add our local Advisor to the existing proxy's Advisor chain...
|
||||
if (this.beforeExistingAdvisors) {
|
||||
advised.addAdvisor(0, this.advisor);
|
||||
}
|
||||
@@ -102,32 +104,47 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
else {
|
||||
ProxyFactory proxyFactory = new ProxyFactory(bean);
|
||||
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
|
||||
proxyFactory.copyFrom(this);
|
||||
proxyFactory.addAdvisor(this.advisor);
|
||||
return proxyFactory.getProxy(this.beanClassLoader);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No async proxy needed.
|
||||
return bean;
|
||||
|
||||
if (isEligible(bean, beanName)) {
|
||||
ProxyFactory proxyFactory = new ProxyFactory(bean);
|
||||
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
|
||||
proxyFactory.copyFrom(this);
|
||||
proxyFactory.addAdvisor(this.advisor);
|
||||
return proxyFactory.getProxy(this.beanClassLoader);
|
||||
}
|
||||
|
||||
// No async proxy needed.
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given bean is eligible for advising with this
|
||||
* post-processor's {@link Advisor}.
|
||||
* <p>Implements caching of {@code canApply} results per bean target class.
|
||||
* <p>Delegates to {@link #isEligible(Class)} for target class checking.
|
||||
* Can be overridden e.g. to specifically exclude certain beans by name.
|
||||
* <p>Note: Only called for regular bean instances but not for existing
|
||||
* proxy instances which implement {@link Advised} and allow for adding
|
||||
* the local {@link Advisor} to the existing proxy's {@link Advisor} chain.
|
||||
* For the latter, {@link #isEligible(Class)} is being called directly,
|
||||
* with the actual target class behind the existing proxy (as determined
|
||||
* by {@link AopUtils#getTargetClass(Object)}).
|
||||
* @param bean the bean instance
|
||||
* @param beanName the name of the bean
|
||||
* @see AopUtils#getTargetClass(Object)
|
||||
* @see AopUtils#canApply(Advisor, Class)
|
||||
* @see #isEligible(Class)
|
||||
*/
|
||||
protected boolean isEligible(Object bean, String beanName) {
|
||||
Class<?> targetClass = AopUtils.getTargetClass(bean);
|
||||
return isEligible(bean.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given class is eligible for advising with this
|
||||
* post-processor's {@link Advisor}.
|
||||
* <p>Implements caching of {@code canApply} results per bean target class.
|
||||
* @param targetClass the class to check against
|
||||
* @see AopUtils#canApply(Advisor, Class)
|
||||
*/
|
||||
protected boolean isEligible(Class<?> targetClass) {
|
||||
Boolean eligible = this.eligibleBeans.get(targetClass);
|
||||
if (eligible != null) {
|
||||
return eligible;
|
||||
|
||||
@@ -261,7 +261,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
if (!Object.class.equals(method.getDeclaringClass()) && !Modifier.isStatic(method.getModifiers()) &&
|
||||
Modifier.isFinal(method.getModifiers())) {
|
||||
logger.warn("Unable to proxy method [" + method + "] because it is final: " +
|
||||
"All calls to this method via a proxy will be routed directly to the proxy.");
|
||||
"All calls to this method via a proxy will NOT be routed to the target instance.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -604,7 +604,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
*/
|
||||
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
|
||||
|
||||
private AdvisedSupport advised;
|
||||
private final AdvisedSupport advised;
|
||||
|
||||
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
|
||||
this.advised = advised;
|
||||
@@ -622,8 +622,8 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
oldProxy = AopContext.setCurrentProxy(proxy);
|
||||
setProxyContext = true;
|
||||
}
|
||||
// May be null Get as late as possible to minimize the time we
|
||||
// "own" the target, in case it comes from a pool.
|
||||
// May be null. Get as late as possible to minimize the time we
|
||||
// "own" the target, in case it comes from a pool...
|
||||
target = getTarget();
|
||||
if (target != null) {
|
||||
targetClass = target.getClass();
|
||||
@@ -689,13 +689,13 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
|
||||
private final MethodProxy methodProxy;
|
||||
|
||||
private boolean protectedMethod;
|
||||
private final boolean publicMethod;
|
||||
|
||||
public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,
|
||||
Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
|
||||
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
|
||||
this.methodProxy = methodProxy;
|
||||
this.protectedMethod = Modifier.isProtected(method.getModifiers());
|
||||
this.publicMethod = Modifier.isPublic(method.getModifiers());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -704,11 +704,11 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
*/
|
||||
@Override
|
||||
protected Object invokeJoinpoint() throws Throwable {
|
||||
if (this.protectedMethod) {
|
||||
return super.invokeJoinpoint();
|
||||
if (this.publicMethod) {
|
||||
return this.methodProxy.invoke(this.target, this.arguments);
|
||||
}
|
||||
else {
|
||||
return this.methodProxy.invoke(this.target, this.arguments);
|
||||
return super.invokeJoinpoint();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -829,8 +829,8 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
// of the target type. If so we know it never needs to have return type
|
||||
// massage and can use a dispatcher.
|
||||
// If the proxy is being exposed, then must use the interceptor the
|
||||
// correct one is already configured. If the target is not static cannot
|
||||
// use a Dispatcher because the target can not then be released.
|
||||
// correct one is already configured. If the target is not static, then
|
||||
// cannot use a dispatcher because the target cannot be released.
|
||||
if (exposeProxy || !isStatic) {
|
||||
return INVOKE_TARGET;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +19,6 @@ package org.springframework.aop.framework;
|
||||
import org.aopalliance.intercept.Interceptor;
|
||||
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
@@ -47,9 +46,8 @@ public class ProxyFactory extends ProxyCreatorSupport {
|
||||
* @param target the target object to be proxied
|
||||
*/
|
||||
public ProxyFactory(Object target) {
|
||||
Assert.notNull(target, "Target object must not be null");
|
||||
setInterfaces(ClassUtils.getAllInterfaces(target));
|
||||
setTarget(target);
|
||||
setInterfaces(ClassUtils.getAllInterfaces(target));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -289,15 +289,15 @@ class TypeConverterDelegate {
|
||||
if (index > - 1) {
|
||||
String enumType = trimmedValue.substring(0, index);
|
||||
String fieldName = trimmedValue.substring(index + 1);
|
||||
ClassLoader loader = this.targetObject.getClass().getClassLoader();
|
||||
ClassLoader cl = this.targetObject.getClass().getClassLoader();
|
||||
try {
|
||||
Class<?> enumValueType = loader.loadClass(enumType);
|
||||
Class<?> enumValueType = ClassUtils.forName(enumType, cl);
|
||||
Field enumField = enumValueType.getField(fieldName);
|
||||
convertedValue = enumField.get(null);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
if(logger.isTraceEnabled()) {
|
||||
logger.trace("Enum class [" + enumType + "] cannot be loaded from [" + loader + "]", ex);
|
||||
logger.trace("Enum class [" + enumType + "] cannot be loaded", ex);
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -135,9 +135,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
public AutowiredAnnotationBeanPostProcessor() {
|
||||
this.autowiredAnnotationTypes.add(Autowired.class);
|
||||
this.autowiredAnnotationTypes.add(Value.class);
|
||||
ClassLoader cl = AutowiredAnnotationBeanPostProcessor.class.getClassLoader();
|
||||
try {
|
||||
this.autowiredAnnotationTypes.add((Class<? extends Annotation>) cl.loadClass("javax.inject.Inject"));
|
||||
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
|
||||
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
|
||||
logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,9 +66,9 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
|
||||
@SuppressWarnings("unchecked")
|
||||
public QualifierAnnotationAutowireCandidateResolver() {
|
||||
this.qualifierTypes.add(Qualifier.class);
|
||||
ClassLoader cl = QualifierAnnotationAutowireCandidateResolver.class.getClassLoader();
|
||||
try {
|
||||
this.qualifierTypes.add((Class<? extends Annotation>) cl.loadClass("javax.inject.Qualifier"));
|
||||
this.qualifierTypes.add((Class<? extends Annotation>)
|
||||
ClassUtils.forName("javax.inject.Qualifier", QualifierAnnotationAutowireCandidateResolver.class.getClassLoader()));
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// JSR-330 API not available - simply skip.
|
||||
|
||||
+10
-7
@@ -38,8 +38,8 @@ import org.springframework.util.StringUtils;
|
||||
/**
|
||||
* Base class for concrete, full-fledged
|
||||
* {@link org.springframework.beans.factory.config.BeanDefinition} classes,
|
||||
* factoring out common properties of {@link RootBeanDefinition} and
|
||||
* {@link ChildBeanDefinition}.
|
||||
* factoring out common properties of {@link GenericBeanDefinition},
|
||||
* {@link RootBeanDefinition} and {@link ChildBeanDefinition}.
|
||||
*
|
||||
* <p>The autowire constants match the ones defined in the
|
||||
* {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory}
|
||||
@@ -123,11 +123,14 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
public static final int DEPENDENCY_CHECK_ALL = 3;
|
||||
|
||||
/**
|
||||
* Constant that indicates the container should attempt to infer the {@link
|
||||
* #setDestroyMethodName destroy method name} for a bean as opposed to explicit
|
||||
* specification of a method name. The value {@value} is specifically designed to
|
||||
* include characters otherwise illegal in a method name, ensuring no possibility of
|
||||
* collisions with legitimately named methods having the same name.
|
||||
* Constant that indicates the container should attempt to infer the
|
||||
* {@link #setDestroyMethodName destroy method name} for a bean as opposed to
|
||||
* explicit specification of a method name. The value {@value} is specifically
|
||||
* designed to include characters otherwise illegal in a method name, ensuring
|
||||
* no possibility of collisions with legitimately named methods having the same
|
||||
* name.
|
||||
* <p>Currently, the method names detected during destroy method inference
|
||||
* are "close" and "shutdown", if present on the specific bean class.
|
||||
*/
|
||||
public static final String INFER_METHOD = "(inferred)";
|
||||
|
||||
|
||||
+2
-2
@@ -105,9 +105,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
private static Class<?> javaxInjectProviderClass = null;
|
||||
|
||||
static {
|
||||
ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();
|
||||
try {
|
||||
javaxInjectProviderClass = cl.loadClass("javax.inject.Provider");
|
||||
javaxInjectProviderClass =
|
||||
ClassUtils.forName("javax.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// JSR-330 API not available - Provider interface simply not supported then.
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -69,7 +69,8 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
|
||||
static {
|
||||
try {
|
||||
closeableInterface = DisposableBeanAdapter.class.getClassLoader().loadClass("java.lang.AutoCloseable");
|
||||
closeableInterface = ClassUtils.forName("java.lang.AutoCloseable",
|
||||
DisposableBeanAdapter.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
closeableInterface = Closeable.class;
|
||||
|
||||
+7
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -89,7 +89,12 @@ public class GenericBeanDefinition extends AbstractBeanDefinition {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Generic bean: " + super.toString();
|
||||
StringBuilder sb = new StringBuilder("Generic bean");
|
||||
if (this.parentName != null) {
|
||||
sb.append(" with parent '").append(this.parentName).append("'");
|
||||
}
|
||||
sb.append(": ").append(super.toString());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,6 +34,7 @@ import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.Constants;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -261,7 +262,7 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
Class<?> cronTriggerClass;
|
||||
Method jobKeyMethod;
|
||||
try {
|
||||
cronTriggerClass = getClass().getClassLoader().loadClass("org.quartz.impl.triggers.CronTriggerImpl");
|
||||
cronTriggerClass = ClassUtils.forName("org.quartz.impl.triggers.CronTriggerImpl", getClass().getClassLoader());
|
||||
jobKeyMethod = JobDetail.class.getMethod("getKey");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,6 +30,7 @@ import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* A Spring {@link FactoryBean} for creating a Quartz {@link org.quartz.JobDetail}
|
||||
@@ -210,7 +211,7 @@ public class JobDetailFactoryBean
|
||||
|
||||
Class<?> jobDetailClass;
|
||||
try {
|
||||
jobDetailClass = getClass().getClassLoader().loadClass("org.quartz.impl.JobDetailImpl");
|
||||
jobDetailClass = ClassUtils.forName("org.quartz.impl.JobDetailImpl", getClass().getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
jobDetailClass = JobDetail.class;
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -87,7 +87,7 @@ public class LocalTaskExecutorThreadPool implements ThreadPool {
|
||||
|
||||
@Override
|
||||
public int blockForAvailableThreads() {
|
||||
// The present implementation always returns 1, making Quartz (1.6)
|
||||
// The present implementation always returns 1, making Quartz
|
||||
// always schedule any tasks that it feels like scheduling.
|
||||
// This could be made smarter for specific TaskExecutors,
|
||||
// for example calling {@code getMaximumPoolSize() - getActiveCount()}
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -87,14 +87,15 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
|
||||
static {
|
||||
try {
|
||||
jobDetailImplClass = Class.forName("org.quartz.impl.JobDetailImpl");
|
||||
jobDetailImplClass = ClassUtils.forName("org.quartz.impl.JobDetailImpl",
|
||||
MethodInvokingJobDetailFactoryBean.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
jobDetailImplClass = null;
|
||||
}
|
||||
try {
|
||||
Class<?> jobExecutionContextClass =
|
||||
QuartzJobBean.class.getClassLoader().loadClass("org.quartz.JobExecutionContext");
|
||||
Class<?> jobExecutionContextClass = ClassUtils.forName("org.quartz.JobExecutionContext",
|
||||
MethodInvokingJobDetailFactoryBean.class.getClassLoader());
|
||||
setResultMethod = jobExecutionContextClass.getMethod("setResult", Object.class);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,6 +28,7 @@ import org.quartz.SchedulerException;
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyAccessorFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -77,7 +78,7 @@ public abstract class QuartzJobBean implements Job {
|
||||
static {
|
||||
try {
|
||||
Class<?> jobExecutionContextClass =
|
||||
QuartzJobBean.class.getClassLoader().loadClass("org.quartz.JobExecutionContext");
|
||||
ClassUtils.forName("org.quartz.JobExecutionContext", QuartzJobBean.class.getClassLoader());
|
||||
getSchedulerMethod = jobExecutionContextClass.getMethod("getScheduler");
|
||||
getMergedJobDataMapMethod = jobExecutionContextClass.getMethod("getMergedJobDataMap");
|
||||
}
|
||||
|
||||
+3
-8
@@ -43,6 +43,7 @@ import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -68,8 +69,8 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
static {
|
||||
// Quartz 2.0 job/trigger key available?
|
||||
try {
|
||||
jobKeyClass = Class.forName("org.quartz.JobKey");
|
||||
triggerKeyClass = Class.forName("org.quartz.TriggerKey");
|
||||
jobKeyClass = ClassUtils.forName("org.quartz.JobKey", SchedulerAccessor.class.getClassLoader());
|
||||
triggerKeyClass = ClassUtils.forName("org.quartz.TriggerKey", SchedulerAccessor.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
jobKeyClass = null;
|
||||
@@ -151,8 +152,6 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* in combination with the Trigger.
|
||||
* @see #setTriggers
|
||||
* @see org.quartz.JobDetail
|
||||
* @see JobDetailBean
|
||||
* @see JobDetailAwareTrigger
|
||||
*/
|
||||
public void setJobDetails(JobDetail... jobDetails) {
|
||||
// Use modifiable ArrayList here, to allow for further adding of
|
||||
@@ -180,15 +179,11 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* "jobDetails" property of this FactoryBean.
|
||||
* @see #setJobDetails
|
||||
* @see org.quartz.JobDetail
|
||||
* @see JobDetailAwareTrigger
|
||||
* @see CronTriggerBean
|
||||
* @see SimpleTriggerBean
|
||||
*/
|
||||
public void setTriggers(Trigger... triggers) {
|
||||
this.triggers = Arrays.asList(triggers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify Quartz SchedulerListeners to be registered with the Scheduler.
|
||||
*/
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,7 @@ import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.Constants;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -245,14 +246,14 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
sti.setRepeatCount(this.repeatCount);
|
||||
sti.setPriority(this.priority);
|
||||
sti.setMisfireInstruction(this.misfireInstruction);
|
||||
cti.setDescription(this.description);
|
||||
sti.setDescription(this.description);
|
||||
this.simpleTrigger = sti;
|
||||
*/
|
||||
|
||||
Class<?> simpleTriggerClass;
|
||||
Method jobKeyMethod;
|
||||
try {
|
||||
simpleTriggerClass = getClass().getClassLoader().loadClass("org.quartz.impl.triggers.SimpleTriggerImpl");
|
||||
simpleTriggerClass = ClassUtils.forName("org.quartz.impl.triggers.SimpleTriggerImpl", getClass().getClassLoader());
|
||||
jobKeyMethod = JobDetail.class.getMethod("getKey");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
|
||||
+6
-3
@@ -372,6 +372,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
|
||||
private final Collection<? extends Cache> caches;
|
||||
|
||||
private final MethodCacheKey methodCacheKey;
|
||||
|
||||
public CacheOperationContext(CacheOperation operation, Method method,
|
||||
Object[] args, Object target, Class<?> targetClass) {
|
||||
this.operation = operation;
|
||||
@@ -380,6 +382,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
this.target = target;
|
||||
this.targetClass = targetClass;
|
||||
this.caches = CacheAspectSupport.this.getCaches(operation);
|
||||
this.methodCacheKey = new MethodCacheKey(method, targetClass);
|
||||
}
|
||||
|
||||
private Object[] extractArgs(Method method, Object[] args) {
|
||||
@@ -396,7 +399,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
protected boolean isConditionPassing(Object result) {
|
||||
if (StringUtils.hasText(this.operation.getCondition())) {
|
||||
EvaluationContext evaluationContext = createEvaluationContext(result);
|
||||
return evaluator.condition(this.operation.getCondition(), this.method, evaluationContext);
|
||||
return evaluator.condition(this.operation.getCondition(), this.methodCacheKey, evaluationContext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -411,7 +414,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
}
|
||||
if (StringUtils.hasText(unless)) {
|
||||
EvaluationContext evaluationContext = createEvaluationContext(value);
|
||||
return !evaluator.unless(unless, this.method, evaluationContext);
|
||||
return !evaluator.unless(unless, this.methodCacheKey, evaluationContext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -423,7 +426,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
protected Object generateKey(Object result) {
|
||||
if (StringUtils.hasText(this.operation.getKey())) {
|
||||
EvaluationContext evaluationContext = createEvaluationContext(result);
|
||||
return evaluator.key(this.operation.getKey(), this.method, evaluationContext);
|
||||
return evaluator.key(this.operation.getKey(), this.methodCacheKey, evaluationContext);
|
||||
}
|
||||
return keyGenerator.generate(this.target, this.method, this.args);
|
||||
}
|
||||
|
||||
Vendored
+52
-22
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,16 +27,19 @@ import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Utility class handling the SpEL expression parsing.
|
||||
* Meant to be used as a reusable, thread-safe component.
|
||||
*
|
||||
* <p>Performs internal caching for performance reasons.
|
||||
* <p>Performs internal caching for performance reasons
|
||||
* using {@link MethodCacheKey}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
* @author Stephane Nicoll
|
||||
* @since 3.1
|
||||
*/
|
||||
class ExpressionEvaluator {
|
||||
@@ -49,13 +52,16 @@ class ExpressionEvaluator {
|
||||
// shared param discoverer since it caches data internally
|
||||
private final ParameterNameDiscoverer paramNameDiscoverer = new DefaultParameterNameDiscoverer();
|
||||
|
||||
private final Map<String, Expression> keyCache = new ConcurrentHashMap<String, Expression>(64);
|
||||
private final Map<ExpressionKey, Expression> keyCache
|
||||
= new ConcurrentHashMap<ExpressionKey, Expression>(64);
|
||||
|
||||
private final Map<String, Expression> conditionCache = new ConcurrentHashMap<String, Expression>(64);
|
||||
private final Map<ExpressionKey, Expression> conditionCache
|
||||
= new ConcurrentHashMap<ExpressionKey, Expression>(64);
|
||||
|
||||
private final Map<String, Expression> unlessCache = new ConcurrentHashMap<String, Expression>(64);
|
||||
private final Map<ExpressionKey, Expression> unlessCache
|
||||
= new ConcurrentHashMap<ExpressionKey, Expression>(64);
|
||||
|
||||
private final Map<String, Method> targetMethodCache = new ConcurrentHashMap<String, Method>(64);
|
||||
private final Map<MethodCacheKey, Method> targetMethodCache = new ConcurrentHashMap<MethodCacheKey, Method>(64);
|
||||
|
||||
|
||||
/**
|
||||
@@ -93,22 +99,22 @@ class ExpressionEvaluator {
|
||||
return evaluationContext;
|
||||
}
|
||||
|
||||
public Object key(String keyExpression, Method method, EvaluationContext evalContext) {
|
||||
return getExpression(this.keyCache, keyExpression, method).getValue(evalContext);
|
||||
public Object key(String keyExpression, MethodCacheKey methodKey, EvaluationContext evalContext) {
|
||||
return getExpression(this.keyCache, keyExpression, methodKey).getValue(evalContext);
|
||||
}
|
||||
|
||||
public boolean condition(String conditionExpression, Method method, EvaluationContext evalContext) {
|
||||
return getExpression(this.conditionCache, conditionExpression, method).getValue(
|
||||
public boolean condition(String conditionExpression, MethodCacheKey methodKey, EvaluationContext evalContext) {
|
||||
return getExpression(this.conditionCache, conditionExpression, methodKey).getValue(
|
||||
evalContext, boolean.class);
|
||||
}
|
||||
|
||||
public boolean unless(String unlessExpression, Method method, EvaluationContext evalContext) {
|
||||
return getExpression(this.unlessCache, unlessExpression, method).getValue(
|
||||
public boolean unless(String unlessExpression, MethodCacheKey methodKey, EvaluationContext evalContext) {
|
||||
return getExpression(this.unlessCache, unlessExpression, methodKey).getValue(
|
||||
evalContext, boolean.class);
|
||||
}
|
||||
|
||||
private Expression getExpression(Map<String, Expression> cache, String expression, Method method) {
|
||||
String key = toString(method, expression);
|
||||
private Expression getExpression(Map<ExpressionKey, Expression> cache, String expression, MethodCacheKey methodKey) {
|
||||
ExpressionKey key = createKey(methodKey, expression);
|
||||
Expression rtn = cache.get(key);
|
||||
if (rtn == null) {
|
||||
rtn = this.parser.parseExpression(expression);
|
||||
@@ -117,13 +123,37 @@ class ExpressionEvaluator {
|
||||
return rtn;
|
||||
}
|
||||
|
||||
private String toString(Method method, String expression) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(method.getDeclaringClass().getName());
|
||||
sb.append("#");
|
||||
sb.append(method.toString());
|
||||
sb.append("#");
|
||||
sb.append(expression);
|
||||
return sb.toString();
|
||||
private ExpressionKey createKey(MethodCacheKey methodCacheKey, String expression) {
|
||||
return new ExpressionKey(methodCacheKey, expression);
|
||||
}
|
||||
|
||||
|
||||
private static class ExpressionKey {
|
||||
private final MethodCacheKey methodCacheKey;
|
||||
private final String expression;
|
||||
|
||||
private ExpressionKey(MethodCacheKey methodCacheKey, String expression) {
|
||||
this.methodCacheKey = methodCacheKey;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof ExpressionKey)) {
|
||||
return false;
|
||||
}
|
||||
ExpressionKey otherKey = (ExpressionKey) other;
|
||||
return (this.methodCacheKey.equals(otherKey.methodCacheKey)
|
||||
&& ObjectUtils.nullSafeEquals(this.expression, otherKey.expression));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.methodCacheKey.hashCode() * 29 + (this.expression != null ? this.expression.hashCode() : 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* (rather then a dedicated 'closure'-like class for deferred execution).
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Stephane Nicoll
|
||||
* @since 3.1
|
||||
*/
|
||||
class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
|
||||
@@ -45,13 +46,13 @@ class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
|
||||
|
||||
private final Class<?> targetClass;
|
||||
|
||||
private final Map<String, Method> methodCache;
|
||||
private final Map<MethodCacheKey, Method> methodCache;
|
||||
|
||||
private boolean paramLoaded = false;
|
||||
|
||||
|
||||
LazyParamAwareEvaluationContext(Object rootObject, ParameterNameDiscoverer paramDiscoverer, Method method,
|
||||
Object[] args, Class<?> targetClass, Map<String, Method> methodCache) {
|
||||
Object[] args, Class<?> targetClass, Map<MethodCacheKey, Method> methodCache) {
|
||||
super(rootObject);
|
||||
|
||||
this.paramDiscoverer = paramDiscoverer;
|
||||
@@ -85,7 +86,7 @@ class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
|
||||
return;
|
||||
}
|
||||
|
||||
String methodKey = toString(this.method);
|
||||
MethodCacheKey methodKey = new MethodCacheKey(this.method, this.targetClass);
|
||||
Method targetMethod = this.methodCache.get(methodKey);
|
||||
if (targetMethod == null) {
|
||||
targetMethod = AopUtils.getMostSpecificMethod(this.method, this.targetClass);
|
||||
@@ -110,11 +111,4 @@ class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
|
||||
}
|
||||
}
|
||||
|
||||
private String toString(Method m) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(m.getDeclaringClass().getName());
|
||||
sb.append("#");
|
||||
sb.append(m.toString());
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author 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
|
||||
*
|
||||
* http://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.cache.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Represent a method on a particular {@link Class} and is suitable as a key.
|
||||
* <p>Mainly for internal use within the framework.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.0.4
|
||||
*/
|
||||
public final class MethodCacheKey {
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Class<?> targetClass;
|
||||
|
||||
public MethodCacheKey(Method method, Class<?> targetClass) {
|
||||
Assert.notNull(method, "method must be set.");
|
||||
this.method = method;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof MethodCacheKey)) {
|
||||
return false;
|
||||
}
|
||||
MethodCacheKey otherKey = (MethodCacheKey) other;
|
||||
return (this.method.equals(otherKey.method) && ObjectUtils.nullSafeEquals(this.targetClass,
|
||||
otherKey.targetClass));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.method.hashCode() * 29 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
|
||||
}
|
||||
|
||||
}
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -226,8 +226,8 @@ public class AnnotationConfigUtils {
|
||||
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
|
||||
RootBeanDefinition def = new RootBeanDefinition();
|
||||
try {
|
||||
ClassLoader cl = AnnotationConfigUtils.class.getClassLoader();
|
||||
def.setBeanClass(cl.loadClass(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME));
|
||||
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
|
||||
AnnotationConfigUtils.class.getClassLoader()));
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new IllegalStateException(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -197,25 +197,26 @@ public @interface Bean {
|
||||
/**
|
||||
* The optional name of a method to call on the bean instance during initialization.
|
||||
* Not commonly used, given that the method may be called programmatically directly
|
||||
* within the body of a Bean-annotated method. Default value is {@code ""}, indicating
|
||||
* that no init method should be called.
|
||||
* within the body of a Bean-annotated method.
|
||||
* <p>The default value is {@code ""}, indicating no init method to be called.
|
||||
*/
|
||||
String initMethod() default "";
|
||||
|
||||
/**
|
||||
* The optional name of a method to call on the bean instance upon closing the
|
||||
* application context, for example a {@code close()} method on a JDBC {@code
|
||||
* DataSource} implementation, or a Hibernate {@code SessionFactory} object.
|
||||
* application context, for example a {@code close()} method on a JDBC
|
||||
* {@code DataSource} implementation, or a Hibernate {@code SessionFactory} object.
|
||||
* The method must have no arguments but may throw any exception.
|
||||
* <p>As a convenience to the user, the container will attempt to infer a destroy
|
||||
* method against an object returned from the {@code @Bean} method. For example, given a
|
||||
* {@code @Bean} method returning an Apache Commons DBCP {@code BasicDataSource}, the
|
||||
* container will notice the {@code close()} method available on that object and
|
||||
* method against an object returned from the {@code @Bean} method. For example, given
|
||||
* an {@code @Bean} method returning an Apache Commons DBCP {@code BasicDataSource},
|
||||
* the container will notice the {@code close()} method available on that object and
|
||||
* automatically register it as the {@code destroyMethod}. This 'destroy method
|
||||
* inference' is currently limited to detecting only public, no-arg methods named
|
||||
* 'close'. The method may be declared at any level of the inheritance hierarchy and
|
||||
* will be detected regardless of the return type of the {@code @Bean} method (i.e.,
|
||||
* detection occurs reflectively against the bean instance itself at creation time).
|
||||
* 'close' or 'shutdown'. The method may be declared at any level of the inheritance
|
||||
* hierarchy and will be detected regardless of the return type of the {@code @Bean}
|
||||
* method (i.e., detection occurs reflectively against the bean instance itself at
|
||||
* creation time).
|
||||
* <p>To disable destroy method inference for a particular {@code @Bean}, specify an
|
||||
* empty string as the value, e.g. {@code @Bean(destroyMethod="")}. Note that the
|
||||
* {@link org.springframework.beans.factory.DisposableBean} and the
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -238,7 +238,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
|
||||
try {
|
||||
this.includeFilters.add(new AnnotationTypeFilter(
|
||||
((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false));
|
||||
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
|
||||
logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
@@ -246,7 +246,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
}
|
||||
try {
|
||||
this.includeFilters.add(new AnnotationTypeFilter(
|
||||
((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false));
|
||||
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
|
||||
logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -142,10 +142,10 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
private static Class<? extends Annotation> ejbRefClass = null;
|
||||
|
||||
static {
|
||||
ClassLoader cl = CommonAnnotationBeanPostProcessor.class.getClassLoader();
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Annotation> clazz = (Class<? extends Annotation>) cl.loadClass("javax.xml.ws.WebServiceRef");
|
||||
Class<? extends Annotation> clazz = (Class<? extends Annotation>)
|
||||
ClassUtils.forName("javax.xml.ws.WebServiceRef", CommonAnnotationBeanPostProcessor.class.getClassLoader());
|
||||
webServiceRefClass = clazz;
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
@@ -153,7 +153,8 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
}
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Annotation> clazz = (Class<? extends Annotation>) cl.loadClass("javax.ejb.EJB");
|
||||
Class<? extends Annotation> clazz = (Class<? extends Annotation>)
|
||||
ClassUtils.forName("javax.ejb.EJB", CommonAnnotationBeanPostProcessor.class.getClassLoader());
|
||||
ejbRefClass = clazz;
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,7 +258,7 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object instantiateUserDefinedStrategy(String className, Class<?> strategyType, ClassLoader classLoader) {
|
||||
Object result = null;
|
||||
Object result;
|
||||
try {
|
||||
result = classLoader.loadClass(className).newInstance();
|
||||
}
|
||||
@@ -268,7 +268,7 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException("Unable to instantiate class [" + className + "] for strategy [" +
|
||||
strategyType.getName() + "]. A zero-argument constructor is required", ex);
|
||||
strategyType.getName() + "]: a zero-argument constructor is required", ex);
|
||||
}
|
||||
|
||||
if (!strategyType.isAssignableFrom(result.getClass())) {
|
||||
|
||||
+11
-18
@@ -116,7 +116,8 @@ class ConfigurationClassParser {
|
||||
|
||||
private final Map<String, ConfigurationClass> knownSuperclasses = new HashMap<String, ConfigurationClass>();
|
||||
|
||||
private final MultiValueMap<String, PropertySource<?>> propertySources = new LinkedMultiValueMap<String, PropertySource<?>>();
|
||||
private final MultiValueMap<String, ResourcePropertySource> propertySources =
|
||||
new LinkedMultiValueMap<String, ResourcePropertySource>();
|
||||
|
||||
private final ImportStack importStack = new ImportStack();
|
||||
|
||||
@@ -267,7 +268,7 @@ class ConfigurationClassParser {
|
||||
// process superclass, if any
|
||||
if (sourceClass.getMetadata().hasSuperClass()) {
|
||||
String superclass = sourceClass.getMetadata().getSuperClassName();
|
||||
if (!this.knownSuperclasses.containsKey(superclass)) {
|
||||
if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
|
||||
this.knownSuperclasses.put(superclass, configClass);
|
||||
// superclass found, return its annotation metadata and recurse
|
||||
try {
|
||||
@@ -305,23 +306,15 @@ class ConfigurationClassParser {
|
||||
String name = propertySource.getString("name");
|
||||
String[] locations = propertySource.getStringArray("value");
|
||||
boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
|
||||
int locationCount = locations.length;
|
||||
if (locationCount == 0) {
|
||||
if (locations.length == 0) {
|
||||
throw new IllegalArgumentException("At least one @PropertySource(value) location is required");
|
||||
}
|
||||
for (String location : locations) {
|
||||
try {
|
||||
Resource resource = this.resourceLoader.getResource(
|
||||
this.environment.resolveRequiredPlaceholders(location));
|
||||
if (!StringUtils.hasText(name) || this.propertySources.containsKey(name)) {
|
||||
// We need to ensure unique names when the property source will
|
||||
// ultimately end up in a composite
|
||||
ResourcePropertySource ps = new ResourcePropertySource(resource);
|
||||
this.propertySources.add((StringUtils.hasText(name) ? name : ps.getName()), ps);
|
||||
}
|
||||
else {
|
||||
this.propertySources.add(name, new ResourcePropertySource(name, resource));
|
||||
}
|
||||
String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
|
||||
Resource resource = this.resourceLoader.getResource(resolvedLocation);
|
||||
ResourcePropertySource ps = new ResourcePropertySource(resource);
|
||||
this.propertySources.add((StringUtils.hasText(name) ? name : ps.getName()), ps);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
// from resolveRequiredPlaceholders
|
||||
@@ -484,15 +477,15 @@ class ConfigurationClassParser {
|
||||
|
||||
public List<PropertySource<?>> getPropertySources() {
|
||||
List<PropertySource<?>> propertySources = new LinkedList<PropertySource<?>>();
|
||||
for (Map.Entry<String, List<PropertySource<?>>> entry : this.propertySources.entrySet()) {
|
||||
for (Map.Entry<String, List<ResourcePropertySource>> entry : this.propertySources.entrySet()) {
|
||||
propertySources.add(0, collatePropertySources(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
return propertySources;
|
||||
}
|
||||
|
||||
private PropertySource<?> collatePropertySources(String name, List<PropertySource<?>> propertySources) {
|
||||
private PropertySource<?> collatePropertySources(String name, List<ResourcePropertySource> propertySources) {
|
||||
if (propertySources.size() == 1) {
|
||||
return propertySources.get(0);
|
||||
return propertySources.get(0).withName(name);
|
||||
}
|
||||
CompositePropertySource result = new CompositePropertySource(name);
|
||||
for (int i = propertySources.size() - 1; i >= 0; i--) {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -307,7 +307,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
"Reason: Environment must implement ConfigurableEnvironment");
|
||||
}
|
||||
else {
|
||||
MutablePropertySources envPropertySources = ((ConfigurableEnvironment)this.environment).getPropertySources();
|
||||
MutablePropertySources envPropertySources = ((ConfigurableEnvironment) this.environment).getPropertySources();
|
||||
for (PropertySource<?> propertySource : parsedPropertySources) {
|
||||
envPropertySources.addLast(propertySource);
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,6 +32,7 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Advisor that activates asynchronous method execution through the {@link Async}
|
||||
@@ -73,9 +74,9 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B
|
||||
public AsyncAnnotationAdvisor(Executor executor) {
|
||||
Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<Class<? extends Annotation>>(2);
|
||||
asyncAnnotationTypes.add(Async.class);
|
||||
ClassLoader cl = AsyncAnnotationAdvisor.class.getClassLoader();
|
||||
try {
|
||||
asyncAnnotationTypes.add((Class<? extends Annotation>) cl.loadClass("javax.ejb.Asynchronous"));
|
||||
asyncAnnotationTypes.add((Class<? extends Annotation>)
|
||||
ClassUtils.forName("javax.ejb.Asynchronous", AsyncAnnotationAdvisor.class.getClassLoader()));
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// If EJB 3.1 API not present, simply ignore.
|
||||
|
||||
+6
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,7 +25,6 @@ import java.util.List;
|
||||
|
||||
import org.jruby.Ruby;
|
||||
import org.jruby.RubyArray;
|
||||
import org.jruby.RubyException;
|
||||
import org.jruby.RubyNil;
|
||||
import org.jruby.ast.ClassNode;
|
||||
import org.jruby.ast.Colon2Node;
|
||||
@@ -116,10 +115,12 @@ public abstract class JRubyScriptUtils {
|
||||
|
||||
/**
|
||||
* Find the first {@link ClassNode} under the supplied {@link Node}.
|
||||
* @return the found {@code ClassNode}, or {@code null}
|
||||
* if no {@link ClassNode} is found
|
||||
* @return the corresponding {@code ClassNode}, or {@code null} if none found
|
||||
*/
|
||||
private static ClassNode findClassNode(Node node) {
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
if (node instanceof ClassNode) {
|
||||
return (ClassNode) node;
|
||||
}
|
||||
@@ -229,9 +230,6 @@ public abstract class JRubyScriptUtils {
|
||||
/**
|
||||
* Exception thrown in response to a JRuby {@link RaiseException}
|
||||
* being thrown from a JRuby method invocation.
|
||||
* <p>Introduced because the {@code RaiseException} class does not
|
||||
* have useful {@link Object#toString()}, {@link Throwable#getMessage()},
|
||||
* and {@link Throwable#printStackTrace} implementations.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public static class JRubyExecutionException extends NestedRuntimeException {
|
||||
@@ -242,12 +240,7 @@ public abstract class JRubyScriptUtils {
|
||||
* @param ex the cause (must not be {@code null})
|
||||
*/
|
||||
public JRubyExecutionException(RaiseException ex) {
|
||||
super(buildMessage(ex), ex);
|
||||
}
|
||||
|
||||
private static String buildMessage(RaiseException ex) {
|
||||
RubyException rubyEx = ex.getException();
|
||||
return (rubyEx != null && rubyEx.message != null) ? rubyEx.message.toString() : "Unexpected JRuby error";
|
||||
super(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+74
-29
@@ -102,6 +102,7 @@ public final class CglibProxyTests extends AbstractAopProxyTests implements Seri
|
||||
@Test
|
||||
public void testProtectedMethodInvocation() {
|
||||
ProtectedMethodTestBean bean = new ProtectedMethodTestBean();
|
||||
bean.value = "foo";
|
||||
mockTargetSource.setTarget(bean);
|
||||
|
||||
AdvisedSupport as = new AdvisedSupport(new Class<?>[]{});
|
||||
@@ -109,8 +110,47 @@ public final class CglibProxyTests extends AbstractAopProxyTests implements Seri
|
||||
as.addAdvice(new NopInterceptor());
|
||||
AopProxy aop = new CglibAopProxy(as);
|
||||
|
||||
Object proxy = aop.getProxy();
|
||||
ProtectedMethodTestBean proxy = (ProtectedMethodTestBean) aop.getProxy();
|
||||
assertTrue(AopUtils.isCglibProxy(proxy));
|
||||
assertEquals(proxy.getClass().getClassLoader(), bean.getClass().getClassLoader());
|
||||
assertEquals("foo", proxy.getString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPackageMethodInvocation() {
|
||||
PackageMethodTestBean bean = new PackageMethodTestBean();
|
||||
bean.value = "foo";
|
||||
mockTargetSource.setTarget(bean);
|
||||
|
||||
AdvisedSupport as = new AdvisedSupport(new Class<?>[]{});
|
||||
as.setTargetSource(mockTargetSource);
|
||||
as.addAdvice(new NopInterceptor());
|
||||
AopProxy aop = new CglibAopProxy(as);
|
||||
|
||||
PackageMethodTestBean proxy = (PackageMethodTestBean) aop.getProxy();
|
||||
assertTrue(AopUtils.isCglibProxy(proxy));
|
||||
assertEquals(proxy.getClass().getClassLoader(), bean.getClass().getClassLoader());
|
||||
assertEquals("foo", proxy.getString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPackageMethodInvocationWithDifferentClassLoader() {
|
||||
ClassLoader child = new ClassLoader(getClass().getClassLoader()) {
|
||||
};
|
||||
|
||||
PackageMethodTestBean bean = new PackageMethodTestBean();
|
||||
bean.value = "foo";
|
||||
mockTargetSource.setTarget(bean);
|
||||
|
||||
AdvisedSupport as = new AdvisedSupport(new Class<?>[]{});
|
||||
as.setTargetSource(mockTargetSource);
|
||||
as.addAdvice(new NopInterceptor());
|
||||
AopProxy aop = new CglibAopProxy(as);
|
||||
|
||||
PackageMethodTestBean proxy = (PackageMethodTestBean) aop.getProxy(child);
|
||||
assertTrue(AopUtils.isCglibProxy(proxy));
|
||||
assertNotEquals(proxy.getClass().getClassLoader(), bean.getClass().getClassLoader());
|
||||
assertNull(proxy.getString()); // we're stuck in the proxy instance
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -410,9 +450,40 @@ public final class CglibProxyTests extends AbstractAopProxyTests implements Seri
|
||||
}
|
||||
|
||||
|
||||
public static class HasFinalMethod {
|
||||
public static class NoArgCtorTestBean {
|
||||
|
||||
public final void foo() {
|
||||
private boolean called = false;
|
||||
|
||||
public NoArgCtorTestBean(String x, int y) {
|
||||
called = true;
|
||||
}
|
||||
|
||||
public boolean wasCalled() {
|
||||
return called;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
called = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ProtectedMethodTestBean {
|
||||
|
||||
public String value;
|
||||
|
||||
protected String getString() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class PackageMethodTestBean {
|
||||
|
||||
public String value;
|
||||
|
||||
String getString() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -436,32 +507,6 @@ class CglibTestBean {
|
||||
}
|
||||
|
||||
|
||||
class NoArgCtorTestBean {
|
||||
|
||||
private boolean called = false;
|
||||
|
||||
public NoArgCtorTestBean(String x, int y) {
|
||||
called = true;
|
||||
}
|
||||
|
||||
public boolean wasCalled() {
|
||||
return called;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
called = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ProtectedMethodTestBean {
|
||||
|
||||
protected String getString() {
|
||||
return "foo";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class UnsupportedInterceptor implements MethodInterceptor {
|
||||
|
||||
@Override
|
||||
|
||||
spring-context/src/test/java/org/springframework/cache/config/ExpressionCachingIntegrationTests.java
Vendored
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author 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
|
||||
*
|
||||
* http://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.cache.config;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.CachePut;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class ExpressionCachingIntegrationTests {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test // SPR-11692
|
||||
public void expressionIsCacheBasedOnActualMethod() {
|
||||
ConfigurableApplicationContext context =
|
||||
new AnnotationConfigApplicationContext(SharedConfig.class, Spr11692Config.class);
|
||||
|
||||
BaseDao<User> userDao = (BaseDao<User>) context.getBean("userDao");
|
||||
BaseDao<Order> orderDao = (BaseDao<Order>) context.getBean("orderDao");
|
||||
|
||||
userDao.persist(new User("1"));
|
||||
orderDao.persist(new Order("2"));
|
||||
|
||||
context.close();
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class Spr11692Config {
|
||||
@Bean
|
||||
public BaseDao<User> userDao() {
|
||||
return new UserDaoImpl();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BaseDao<Order> orderDao() {
|
||||
return new OrderDaoImpl();
|
||||
}
|
||||
}
|
||||
|
||||
private static interface BaseDao<T> {
|
||||
T persist(T t);
|
||||
}
|
||||
|
||||
private static class UserDaoImpl implements BaseDao<User> {
|
||||
@Override
|
||||
@CachePut(value = "users", key = "#user.id")
|
||||
public User persist(User user) {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
private static class OrderDaoImpl implements BaseDao<Order> {
|
||||
@Override
|
||||
@CachePut(value = "orders", key = "#order.id")
|
||||
public Order persist(Order order) {
|
||||
return order;
|
||||
}
|
||||
}
|
||||
|
||||
private static class User {
|
||||
private final String id;
|
||||
|
||||
private User(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Order {
|
||||
private final String id;
|
||||
|
||||
private Order(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
static class SharedConfig {
|
||||
@Bean
|
||||
public CacheManager cacheManager() {
|
||||
return new ConcurrentMapCacheManager();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+6
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,6 +39,7 @@ import static org.junit.Assert.*;
|
||||
* @author Costin Leau
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class ExpressionEvaluatorTests {
|
||||
|
||||
@@ -82,8 +83,10 @@ public class ExpressionEvaluatorTests {
|
||||
|
||||
Iterator<CacheOperation> it = ops.iterator();
|
||||
|
||||
Object keyA = eval.key(it.next().getKey(), method, evalCtx);
|
||||
Object keyB = eval.key(it.next().getKey(), method, evalCtx);
|
||||
MethodCacheKey key = new MethodCacheKey(method, AnnotatedClass.class);
|
||||
|
||||
Object keyA = eval.key(it.next().getKey(), key, evalCtx);
|
||||
Object keyB = eval.key(it.next().getKey(), key, evalCtx);
|
||||
|
||||
assertEquals(args[0], keyA);
|
||||
assertEquals(args[1], keyB);
|
||||
|
||||
+54
@@ -23,6 +23,7 @@ import org.junit.Test;
|
||||
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
|
||||
import org.springframework.aop.interceptor.SimpleTraceInterceptor;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
@@ -55,6 +56,39 @@ public class BeanMethodPolymorphismTests {
|
||||
assertTrue(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanMethodOverridingOnASM() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.registerBeanDefinition("config", new RootBeanDefinition(OverridingConfig.class.getName()));
|
||||
ctx.setAllowBeanDefinitionOverriding(false);
|
||||
ctx.refresh();
|
||||
assertFalse(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
|
||||
assertEquals("overridden", ctx.getBean("testBean", TestBean.class).toString());
|
||||
assertTrue(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanMethodOverridingWithNarrowedReturnType() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(NarrowedOverridingConfig.class);
|
||||
ctx.setAllowBeanDefinitionOverriding(false);
|
||||
ctx.refresh();
|
||||
assertFalse(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
|
||||
assertEquals("overridden", ctx.getBean("testBean", TestBean.class).toString());
|
||||
assertTrue(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanMethodOverridingWithNarrowedReturnTypeOnASM() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.registerBeanDefinition("config", new RootBeanDefinition(NarrowedOverridingConfig.class.getName()));
|
||||
ctx.setAllowBeanDefinitionOverriding(false);
|
||||
ctx.refresh();
|
||||
assertFalse(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
|
||||
assertEquals("overridden", ctx.getBean("testBean", TestBean.class).toString());
|
||||
assertTrue(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanMethodOverloadingWithoutInheritance() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
@@ -173,6 +207,26 @@ public class BeanMethodPolymorphismTests {
|
||||
}
|
||||
|
||||
|
||||
static class ExtendedTestBean extends TestBean {
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class NarrowedOverridingConfig extends BaseConfig {
|
||||
|
||||
@Bean @Lazy
|
||||
@Override
|
||||
public ExtendedTestBean testBean() {
|
||||
return new ExtendedTestBean() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "overridden";
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class ConfigWithOverloading {
|
||||
|
||||
|
||||
+15
-20
@@ -23,6 +23,7 @@ import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.scope.ScopedObject;
|
||||
import org.springframework.aop.scope.ScopedProxyUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
@@ -86,8 +87,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
*/
|
||||
@Test
|
||||
public void alreadyLoadedConfigurationClasses() {
|
||||
beanFactory.registerBeanDefinition("unloadedConfig", new RootBeanDefinition(UnloadedConfig.class.getName(),
|
||||
null, null));
|
||||
beanFactory.registerBeanDefinition("unloadedConfig", new RootBeanDefinition(UnloadedConfig.class.getName()));
|
||||
beanFactory.registerBeanDefinition("loadedConfig", new RootBeanDefinition(LoadedConfig.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
@@ -126,56 +126,56 @@ public class ConfigurationClassPostProcessorTests {
|
||||
@Test
|
||||
public void postProcessorWorksWithComposedConfigurationWithAttributeOverridesUsingReflection() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
ComposedConfigurationWithAttributeOverridesClass.class);
|
||||
ComposedConfigurationWithAttributeOverridesClass.class);
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithComposedConfigurationWithAttributeOverridesUsingAsm() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
ComposedConfigurationWithAttributeOverridesClass.class.getName());
|
||||
ComposedConfigurationWithAttributeOverridesClass.class.getName());
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithComposedComposedConfigurationWithAttributeOverridesUsingReflection() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
ComposedComposedConfigurationWithAttributeOverridesClass.class);
|
||||
ComposedComposedConfigurationWithAttributeOverridesClass.class);
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithComposedComposedConfigurationWithAttributeOverridesUsingAsm() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
ComposedComposedConfigurationWithAttributeOverridesClass.class.getName());
|
||||
ComposedComposedConfigurationWithAttributeOverridesClass.class.getName());
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesUsingReflection() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
MetaComponentScanConfigurationWithAttributeOverridesClass.class);
|
||||
MetaComponentScanConfigurationWithAttributeOverridesClass.class);
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesUsingAsm() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
MetaComponentScanConfigurationWithAttributeOverridesClass.class.getName());
|
||||
MetaComponentScanConfigurationWithAttributeOverridesClass.class.getName());
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesSubclassUsingReflection() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
SubMetaComponentScanConfigurationWithAttributeOverridesClass.class);
|
||||
SubMetaComponentScanConfigurationWithAttributeOverridesClass.class);
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesSubclassUsingAsm() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
SubMetaComponentScanConfigurationWithAttributeOverridesClass.class.getName());
|
||||
SubMetaComponentScanConfigurationWithAttributeOverridesClass.class.getName());
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@@ -208,8 +208,8 @@ public class ConfigurationClassPostProcessorTests {
|
||||
public void postProcessorDoesNotOverrideRegularBeanDefinitionsEvenWithScopedProxy() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
|
||||
rbd.setResource(new DescriptiveResource("XML or something"));
|
||||
BeanDefinitionHolder proxied = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(rbd, "bar"),
|
||||
beanFactory, true);
|
||||
BeanDefinitionHolder proxied = ScopedProxyUtils.createScopedProxy(
|
||||
new BeanDefinitionHolder(rbd, "bar"), beanFactory, true);
|
||||
beanFactory.registerBeanDefinition("bar", proxied.getBeanDefinition());
|
||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(SingletonBeanConfig.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
@@ -296,8 +296,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(RepositoryInjectionBean.class);
|
||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
beanFactory.registerBeanDefinition("annotatedBean", bd);
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(
|
||||
ScopedProxyRepositoryConfiguration.class));
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(ScopedProxyRepositoryConfiguration.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
beanFactory.freezeConfiguration();
|
||||
@@ -332,8 +331,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(RepositoryFactoryBeanInjectionBean.class);
|
||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
beanFactory.registerBeanDefinition("annotatedBean", bd);
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(
|
||||
RepositoryFactoryBeanConfiguration.class));
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryFactoryBeanConfiguration.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
beanFactory.preInstantiateSingletons();
|
||||
@@ -374,8 +372,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithWildcardWithGenericExtendsMatch() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(
|
||||
WildcardWithGenericExtendsConfiguration.class));
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardWithGenericExtendsConfiguration.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
|
||||
@@ -574,7 +571,6 @@ public class ConfigurationClassPostProcessorTests {
|
||||
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||
public Repository<String> stringRepo() {
|
||||
return new Repository<String>() {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Repository<String>";
|
||||
@@ -586,7 +582,6 @@ public class ConfigurationClassPostProcessorTests {
|
||||
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||
public Repository<Integer> integerRepo() {
|
||||
return new Repository<Integer>() {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Repository<Integer>";
|
||||
|
||||
+8
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -123,6 +123,7 @@ public class NestedConfigurationClassTests {
|
||||
|
||||
@Configuration
|
||||
static class L0Config {
|
||||
|
||||
@Bean
|
||||
public TestBean l0Bean() {
|
||||
return new TestBean("l0");
|
||||
@@ -135,6 +136,7 @@ public class NestedConfigurationClassTests {
|
||||
|
||||
@Configuration
|
||||
static class L1Config {
|
||||
|
||||
@Bean
|
||||
public TestBean l1Bean() {
|
||||
return new TestBean("l1");
|
||||
@@ -147,6 +149,7 @@ public class NestedConfigurationClassTests {
|
||||
|
||||
@Configuration
|
||||
protected static class L2Config {
|
||||
|
||||
@Bean
|
||||
public TestBean l2Bean() {
|
||||
return new TestBean("l2");
|
||||
@@ -163,6 +166,7 @@ public class NestedConfigurationClassTests {
|
||||
|
||||
@Component
|
||||
static class L0ConfigLight {
|
||||
|
||||
@Bean
|
||||
public TestBean l0Bean() {
|
||||
return new TestBean("l0");
|
||||
@@ -175,6 +179,7 @@ public class NestedConfigurationClassTests {
|
||||
|
||||
@Component
|
||||
static class L1ConfigLight {
|
||||
|
||||
@Bean
|
||||
public TestBean l1Bean() {
|
||||
return new TestBean("l1");
|
||||
@@ -187,6 +192,7 @@ public class NestedConfigurationClassTests {
|
||||
|
||||
@Component
|
||||
protected static class L2ConfigLight {
|
||||
|
||||
@Bean
|
||||
public TestBean l2Bean() {
|
||||
return new TestBean("l2");
|
||||
@@ -216,6 +222,7 @@ public class NestedConfigurationClassTests {
|
||||
|
||||
@Configuration
|
||||
static class S1Config extends L0Config {
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public TestBean overrideBean() {
|
||||
|
||||
+47
-25
@@ -124,21 +124,14 @@ public class PropertySourceAnnotationTests {
|
||||
System.clearProperty("path.to.properties");
|
||||
}
|
||||
|
||||
/**
|
||||
* Corner bug reported in SPR-9127.
|
||||
*/
|
||||
@Test
|
||||
public void withNameAndMultipleResourceLocations() {
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void withEmptyResourceLocations() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithNameAndMultipleResourceLocations.class);
|
||||
ctx.register(ConfigWithEmptyResourceLocations.class);
|
||||
ctx.refresh();
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p1"), is(true));
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p2"), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* SPR-10820
|
||||
*/
|
||||
// SPR-10820
|
||||
@Test
|
||||
public void orderingWithAndWithoutNameAndMultipleResourceLocations() {
|
||||
// p2 should 'win' as it was registered last
|
||||
@@ -148,11 +141,22 @@ public class PropertySourceAnnotationTests {
|
||||
assertThat(ctxWithName.getEnvironment().getProperty("testbean.name"), equalTo("p2TestBean"));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void withEmptyResourceLocations() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithEmptyResourceLocations.class);
|
||||
ctx.refresh();
|
||||
@Test
|
||||
public void withNameAndMultipleResourceLocations() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithNameAndMultipleResourceLocations.class);
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p1"), is(true));
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p2"), is(true));
|
||||
// p2 should 'win' as it was registered last
|
||||
assertThat(ctx.getEnvironment().getProperty("testbean.name"), equalTo("p2TestBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withMultipleResourceLocations() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithMultipleResourceLocations.class);
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p1"), is(true));
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p2"), is(true));
|
||||
// p2 should 'win' as it was registered last
|
||||
assertThat(ctx.getEnvironment().getProperty("testbean.name"), equalTo("p2TestBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -164,6 +168,15 @@ public class PropertySourceAnnotationTests {
|
||||
assertThat(ctx.getEnvironment().getProperty("testbean.name"), equalTo("p2TestBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withNamedPropertySources() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithNamedPropertySources.class);
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p1"), is(true));
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p2"), is(true));
|
||||
// p2 should 'win' as it was registered last
|
||||
assertThat(ctx.getEnvironment().getProperty("testbean.name"), equalTo("p2TestBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withMissingPropertySource() {
|
||||
thrown.expect(BeanDefinitionStoreException.class);
|
||||
@@ -263,8 +276,8 @@ public class PropertySourceAnnotationTests {
|
||||
|
||||
@Configuration
|
||||
@PropertySources({
|
||||
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/p1.properties"),
|
||||
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/p2.properties")
|
||||
@PropertySource("classpath:org/springframework/context/annotation/p1.properties"),
|
||||
@PropertySource("classpath:org/springframework/context/annotation/p2.properties"),
|
||||
})
|
||||
static class ConfigWithPropertySources {
|
||||
}
|
||||
@@ -272,9 +285,18 @@ public class PropertySourceAnnotationTests {
|
||||
|
||||
@Configuration
|
||||
@PropertySources({
|
||||
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/p1.properties"),
|
||||
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/missing.properties"),
|
||||
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/p2.properties")
|
||||
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/p1.properties"),
|
||||
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/p2.properties"),
|
||||
})
|
||||
static class ConfigWithNamedPropertySources {
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySources({
|
||||
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/p1.properties"),
|
||||
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/missing.properties"),
|
||||
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/p2.properties")
|
||||
})
|
||||
static class ConfigWithMissingPropertySource {
|
||||
}
|
||||
@@ -282,10 +304,10 @@ public class PropertySourceAnnotationTests {
|
||||
|
||||
@Configuration
|
||||
@PropertySources({
|
||||
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/p1.properties"),
|
||||
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/missing.properties", ignoreResourceNotFound=true),
|
||||
@PropertySource(name = "psName", value="classpath:${myPath}/missing.properties", ignoreResourceNotFound=true),
|
||||
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/p2.properties")
|
||||
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/p1.properties"),
|
||||
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/missing.properties", ignoreResourceNotFound=true),
|
||||
@PropertySource(name = "psName", value = "classpath:${myPath}/missing.properties", ignoreResourceNotFound=true),
|
||||
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/p2.properties")
|
||||
})
|
||||
static class ConfigWithIgnoredPropertySource {
|
||||
}
|
||||
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author 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
|
||||
*
|
||||
* http://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.configuration;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.context.annotation.ScopedProxyMode;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class Spr10744Tests {
|
||||
|
||||
private static int createCount = 0;
|
||||
|
||||
private static int scopeCount = 0;
|
||||
|
||||
|
||||
@Test
|
||||
public void testSpr10744() throws Exception {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.getBeanFactory().registerScope("myTestScope", new MyTestScope());
|
||||
context.register(MyTestConfiguration.class);
|
||||
context.refresh();
|
||||
|
||||
Foo bean1 = context.getBean("foo", Foo.class);
|
||||
Foo bean2 = context.getBean("foo", Foo.class);
|
||||
assertThat(bean1, sameInstance(bean2));
|
||||
|
||||
// Should not have invoked constructor for the proxy instance
|
||||
assertThat(createCount, equalTo(0));
|
||||
assertThat(scopeCount, equalTo(0));
|
||||
|
||||
// Proxy mode should create new scoped object on each method call
|
||||
bean1.getMessage();
|
||||
assertThat(createCount, equalTo(1));
|
||||
assertThat(scopeCount, equalTo(1));
|
||||
bean1.getMessage();
|
||||
assertThat(createCount, equalTo(2));
|
||||
assertThat(scopeCount, equalTo(2));
|
||||
|
||||
context.close();
|
||||
}
|
||||
|
||||
|
||||
private static class MyTestScope implements org.springframework.beans.factory.config.Scope {
|
||||
|
||||
@Override
|
||||
public Object get(String name, ObjectFactory<?> objectFactory) {
|
||||
scopeCount++;
|
||||
return objectFactory.getObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerDestructionCallback(String name, Runnable callback) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveContextualObject(String key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConversationId() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class Foo {
|
||||
|
||||
public Foo() {
|
||||
createCount++;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return "Hello";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class MyConfiguration {
|
||||
|
||||
@Bean
|
||||
public Foo foo() {
|
||||
return new Foo();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class MyTestConfiguration extends MyConfiguration {
|
||||
|
||||
@Bean
|
||||
@Scope(value = "myTestScope", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||
@Override
|
||||
public Foo foo() {
|
||||
return new Foo();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+211
-7
@@ -18,19 +18,22 @@ package org.springframework.scheduling.annotation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
||||
import org.springframework.aop.support.DefaultIntroductionAdvisor;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.tests.Assume;
|
||||
import org.springframework.tests.TestGroup;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@@ -46,10 +49,6 @@ public class AsyncExecutionTests {
|
||||
|
||||
private static int listenerConstructed = 0;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Assume.group(TestGroup.PERFORMANCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethods() throws Exception {
|
||||
@@ -135,6 +134,46 @@ public class AsyncExecutionTests {
|
||||
assertEquals("20", future.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncClassWithPostProcessor() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncClassBean.class));
|
||||
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
|
||||
context.refresh();
|
||||
AsyncClassBean asyncTest = context.getBean("asyncTest", AsyncClassBean.class);
|
||||
asyncTest.doSomething(10);
|
||||
Future<String> future = asyncTest.returnSomething(20);
|
||||
assertEquals("20", future.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncClassWithInterface() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncClassBeanWithInterface.class));
|
||||
context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class));
|
||||
context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class));
|
||||
context.refresh();
|
||||
RegularInterface asyncTest = context.getBean("asyncTest", RegularInterface.class);
|
||||
asyncTest.doSomething(10);
|
||||
Future<String> future = asyncTest.returnSomething(20);
|
||||
assertEquals("20", future.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncClassWithInterfaceAndPostProcessor() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncClassBeanWithInterface.class));
|
||||
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
|
||||
context.refresh();
|
||||
RegularInterface asyncTest = context.getBean("asyncTest", RegularInterface.class);
|
||||
asyncTest.doSomething(10);
|
||||
Future<String> future = asyncTest.returnSomething(20);
|
||||
assertEquals("20", future.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncInterface() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
@@ -149,6 +188,46 @@ public class AsyncExecutionTests {
|
||||
assertEquals("20", future.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncInterfaceWithPostProcessor() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncInterfaceBean.class));
|
||||
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
|
||||
context.refresh();
|
||||
AsyncInterface asyncTest = context.getBean("asyncTest", AsyncInterface.class);
|
||||
asyncTest.doSomething(10);
|
||||
Future<String> future = asyncTest.returnSomething(20);
|
||||
assertEquals("20", future.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dynamicAsyncInterface() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(DynamicAsyncInterfaceBean.class));
|
||||
context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class));
|
||||
context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class));
|
||||
context.refresh();
|
||||
AsyncInterface asyncTest = context.getBean("asyncTest", AsyncInterface.class);
|
||||
asyncTest.doSomething(10);
|
||||
Future<String> future = asyncTest.returnSomething(20);
|
||||
assertEquals("20", future.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dynamicAsyncInterfaceWithPostProcessor() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(DynamicAsyncInterfaceBean.class));
|
||||
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
|
||||
context.refresh();
|
||||
AsyncInterface asyncTest = context.getBean("asyncTest", AsyncInterface.class);
|
||||
asyncTest.doSomething(10);
|
||||
Future<String> future = asyncTest.returnSomething(20);
|
||||
assertEquals("20", future.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethodsInInterface() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
@@ -164,6 +243,33 @@ public class AsyncExecutionTests {
|
||||
assertEquals("20", future.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethodsInInterfaceWithPostProcessor() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncMethodsInterfaceBean.class));
|
||||
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
|
||||
context.refresh();
|
||||
AsyncMethodsInterface asyncTest = context.getBean("asyncTest", AsyncMethodsInterface.class);
|
||||
asyncTest.doNothing(5);
|
||||
asyncTest.doSomething(10);
|
||||
Future<String> future = asyncTest.returnSomething(20);
|
||||
assertEquals("20", future.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dynamicAsyncMethodsInInterfaceWithPostProcessor() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(DynamicAsyncMethodsInterfaceBean.class));
|
||||
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
|
||||
context.refresh();
|
||||
AsyncMethodsInterface asyncTest = context.getBean("asyncTest", AsyncMethodsInterface.class);
|
||||
asyncTest.doSomething(10);
|
||||
Future<String> future = asyncTest.returnSomething(20);
|
||||
assertEquals("20", future.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethodListener() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
@@ -304,6 +410,28 @@ public class AsyncExecutionTests {
|
||||
}
|
||||
|
||||
|
||||
public interface RegularInterface {
|
||||
|
||||
void doSomething(int i);
|
||||
|
||||
Future<String> returnSomething(int i);
|
||||
}
|
||||
|
||||
|
||||
@Async
|
||||
public static class AsyncClassBeanWithInterface implements RegularInterface {
|
||||
|
||||
public void doSomething(int i) {
|
||||
assertTrue(!Thread.currentThread().getName().equals(originalThreadName));
|
||||
}
|
||||
|
||||
public Future<String> returnSomething(int i) {
|
||||
assertTrue(!Thread.currentThread().getName().equals(originalThreadName));
|
||||
return new AsyncResult<String>(Integer.toString(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Async
|
||||
public interface AsyncInterface {
|
||||
|
||||
@@ -328,6 +456,44 @@ public class AsyncExecutionTests {
|
||||
}
|
||||
|
||||
|
||||
public static class DynamicAsyncInterfaceBean implements FactoryBean<AsyncInterface> {
|
||||
|
||||
private final AsyncInterface proxy;
|
||||
|
||||
public DynamicAsyncInterfaceBean() {
|
||||
ProxyFactory pf = new ProxyFactory(new HashMap<>());
|
||||
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new MethodInterceptor() {
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
assertTrue(!Thread.currentThread().getName().equals(originalThreadName));
|
||||
if (Future.class.equals(invocation.getMethod().getReturnType())) {
|
||||
return new AsyncResult<String>(invocation.getArguments()[0].toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
advisor.addInterface(AsyncInterface.class);
|
||||
pf.addAdvisor(advisor);
|
||||
this.proxy = (AsyncInterface) pf.getProxy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncInterface getObject() {
|
||||
return this.proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return this.proxy.getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface AsyncMethodsInterface {
|
||||
|
||||
void doNothing(int i);
|
||||
@@ -360,6 +526,44 @@ public class AsyncExecutionTests {
|
||||
}
|
||||
|
||||
|
||||
public static class DynamicAsyncMethodsInterfaceBean implements FactoryBean<AsyncMethodsInterface> {
|
||||
|
||||
private final AsyncMethodsInterface proxy;
|
||||
|
||||
public DynamicAsyncMethodsInterfaceBean() {
|
||||
ProxyFactory pf = new ProxyFactory(new HashMap<>());
|
||||
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new MethodInterceptor() {
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
assertTrue(!Thread.currentThread().getName().equals(originalThreadName));
|
||||
if (Future.class.equals(invocation.getMethod().getReturnType())) {
|
||||
return new AsyncResult<String>(invocation.getArguments()[0].toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
advisor.addInterface(AsyncMethodsInterface.class);
|
||||
pf.addAdvisor(advisor);
|
||||
this.proxy = (AsyncMethodsInterface) pf.getProxy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncMethodsInterface getObject() {
|
||||
return this.proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return this.proxy.getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class AsyncMethodListener implements ApplicationListener<ApplicationEvent> {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
@@ -17,19 +16,10 @@
|
||||
|
||||
package org.springframework.tests.sample.beans;
|
||||
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
||||
public class Employee extends TestBean {
|
||||
|
||||
private String co;
|
||||
|
||||
/**
|
||||
* Constructor for Employee.
|
||||
*/
|
||||
public Employee() {
|
||||
super();
|
||||
}
|
||||
|
||||
public String getCompany() {
|
||||
return co;
|
||||
}
|
||||
|
||||
@@ -193,9 +193,11 @@ public abstract class ClassVisitor {
|
||||
*/
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
/* SPRING PATCH: REMOVED FOR COMPATIBILITY WITH CGLIB 3.1
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
*/
|
||||
if (cv != null) {
|
||||
return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
}
|
||||
|
||||
@@ -756,7 +756,7 @@ public class ClassWriter extends ClassVisitor {
|
||||
if (innerClasses == null) {
|
||||
innerClasses = new ByteVector();
|
||||
}
|
||||
// §4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the
|
||||
// Sec. 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the
|
||||
// constant_pool table which represents a class or interface C that is
|
||||
// not a package member must have exactly one corresponding entry in the
|
||||
// classes array". To avoid duplicates we keep track in the intVal field
|
||||
|
||||
@@ -116,9 +116,11 @@ public abstract class FieldVisitor {
|
||||
*/
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
/* SPRING PATCH: REMOVED FOR COMPATIBILITY WITH CGLIB 3.1
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
*/
|
||||
if (fv != null) {
|
||||
return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
}
|
||||
|
||||
@@ -1426,16 +1426,20 @@ final class Frame {
|
||||
| cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE);
|
||||
} else {
|
||||
// if u and t are array types, but not with the same element
|
||||
// type, merge(u,t)=java/lang/Object
|
||||
v = OBJECT | cw.addType("java/lang/Object");
|
||||
// type, merge(u,t) = dim(u) - 1 | java/lang/Object
|
||||
int vdim = ELEMENT_OF + (u & DIM);
|
||||
v = vdim | OBJECT | cw.addType("java/lang/Object");
|
||||
}
|
||||
} else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) {
|
||||
// if t is any other reference or array type, the merged type
|
||||
// is Object, or min(dim(u), dim(t)) | java/lang/Object is u
|
||||
// and t have different array dimensions
|
||||
int tdim = t & DIM;
|
||||
int udim = u & DIM;
|
||||
v = (udim != tdim ? Math.min(tdim, udim) : 0) | OBJECT
|
||||
// is min(udim, tdim) | java/lang/Object, where udim is the
|
||||
// array dimension of u, minus 1 if u is an array type with a
|
||||
// primitive element type (and similarly for tdim).
|
||||
int tdim = (((t & DIM) == 0 || (t & BASE_KIND) == OBJECT) ? 0
|
||||
: ELEMENT_OF) + (t & DIM);
|
||||
int udim = (((u & DIM) == 0 || (u & BASE_KIND) == OBJECT) ? 0
|
||||
: ELEMENT_OF) + (u & DIM);
|
||||
v = Math.min(tdim, udim) | OBJECT
|
||||
| cw.addType("java/lang/Object");
|
||||
} else {
|
||||
// if t is any other type, merge(u,t)=TOP
|
||||
|
||||
@@ -110,9 +110,11 @@ public abstract class MethodVisitor {
|
||||
* allowed (see {@link Opcodes}).
|
||||
*/
|
||||
public void visitParameter(String name, int access) {
|
||||
/* SPRING PATCH: REMOVED FOR COMPATIBILITY WITH CGLIB 3.1
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
*/
|
||||
if (mv != null) {
|
||||
mv.visitParameter(name, access);
|
||||
}
|
||||
@@ -179,9 +181,11 @@ public abstract class MethodVisitor {
|
||||
*/
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
/* SPRING PATCH: REMOVED FOR COMPATIBILITY WITH CGLIB 3.1
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
*/
|
||||
if (mv != null) {
|
||||
return mv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
}
|
||||
@@ -693,9 +697,11 @@ public abstract class MethodVisitor {
|
||||
*/
|
||||
public AnnotationVisitor visitInsnAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
/* SPRING PATCH: REMOVED FOR COMPATIBILITY WITH CGLIB 3.1
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
*/
|
||||
if (mv != null) {
|
||||
return mv.visitInsnAnnotation(typeRef, typePath, desc, visible);
|
||||
}
|
||||
@@ -753,9 +759,11 @@ public abstract class MethodVisitor {
|
||||
*/
|
||||
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
/* SPRING PATCH: REMOVED FOR COMPATIBILITY WITH CGLIB 3.1
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
*/
|
||||
if (mv != null) {
|
||||
return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
|
||||
}
|
||||
@@ -824,9 +832,11 @@ public abstract class MethodVisitor {
|
||||
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
|
||||
TypePath typePath, Label[] start, Label[] end, int[] index,
|
||||
String desc, boolean visible) {
|
||||
/* SPRING PATCH: REMOVED FOR COMPATIBILITY WITH CGLIB 3.1
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
*/
|
||||
if (mv != null) {
|
||||
return mv.visitLocalVariableAnnotation(typeRef, typePath, start,
|
||||
end, index, desc, visible);
|
||||
|
||||
+33
-31
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -103,8 +103,8 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
|
||||
// We couldn't load the class file, which is not fatal as it
|
||||
// simply means this method of discovering parameter names won't work.
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cannot find '.class' file for class [" + clazz
|
||||
+ "] - unable to determine constructors/methods parameter names");
|
||||
logger.debug("Cannot find '.class' file for class [" + clazz +
|
||||
"] - unable to determine constructor/method parameter names");
|
||||
}
|
||||
return NO_DEBUG_INFO_MAP;
|
||||
}
|
||||
@@ -117,14 +117,14 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
|
||||
catch (IOException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Exception thrown while reading '.class' file for class [" + clazz +
|
||||
"] - unable to determine constructors/methods parameter names", ex);
|
||||
"] - unable to determine constructor/method parameter names", ex);
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ASM ClassReader failed to parse class file [" + clazz +
|
||||
"], probably due to a new Java class file version that isn't supported yet " +
|
||||
"- unable to determine constructors/methods parameter names", ex);
|
||||
"- unable to determine constructor/method parameter names", ex);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
@@ -148,6 +148,7 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
|
||||
private static final String STATIC_CLASS_INIT = "<clinit>";
|
||||
|
||||
private final Class<?> clazz;
|
||||
|
||||
private final Map<Member, String[]> memberMap;
|
||||
|
||||
public ParameterNameDiscoveringVisitor(Class<?> clazz, Map<Member, String[]> memberMap) {
|
||||
@@ -180,12 +181,17 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
|
||||
private static final String CONSTRUCTOR = "<init>";
|
||||
|
||||
private final Class<?> clazz;
|
||||
|
||||
private final Map<Member, String[]> memberMap;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final Type[] args;
|
||||
|
||||
private final String[] parameterNames;
|
||||
|
||||
private final boolean isStatic;
|
||||
|
||||
private String[] parameterNames;
|
||||
private boolean hasLvtInfo = false;
|
||||
|
||||
/*
|
||||
@@ -194,25 +200,22 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
|
||||
*/
|
||||
private final int[] lvtSlotIndex;
|
||||
|
||||
public LocalVariableTableVisitor(Class<?> clazz, Map<Member, String[]> map, String name, String desc,
|
||||
boolean isStatic) {
|
||||
public LocalVariableTableVisitor(Class<?> clazz, Map<Member, String[]> map, String name, String desc, boolean isStatic) {
|
||||
super(SpringAsmInfo.ASM_VERSION);
|
||||
this.clazz = clazz;
|
||||
this.memberMap = map;
|
||||
this.name = name;
|
||||
// determine args
|
||||
args = Type.getArgumentTypes(desc);
|
||||
this.parameterNames = new String[args.length];
|
||||
this.args = Type.getArgumentTypes(desc);
|
||||
this.parameterNames = new String[this.args.length];
|
||||
this.isStatic = isStatic;
|
||||
this.lvtSlotIndex = computeLvtSlotIndices(isStatic, args);
|
||||
this.lvtSlotIndex = computeLvtSlotIndices(isStatic, this.args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(String name, String description, String signature, Label start, Label end,
|
||||
int index) {
|
||||
public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) {
|
||||
this.hasLvtInfo = true;
|
||||
for (int i = 0; i < lvtSlotIndex.length; i++) {
|
||||
if (lvtSlotIndex[i] == index) {
|
||||
for (int i = 0; i < this.lvtSlotIndex.length; i++) {
|
||||
if (this.lvtSlotIndex[i] == index) {
|
||||
this.parameterNames[i] = name;
|
||||
}
|
||||
}
|
||||
@@ -225,27 +228,25 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
|
||||
// which doesn't use any local variables.
|
||||
// This means that hasLvtInfo could be false for that kind of methods
|
||||
// even if the class has local variable info.
|
||||
memberMap.put(resolveMember(), parameterNames);
|
||||
this.memberMap.put(resolveMember(), this.parameterNames);
|
||||
}
|
||||
}
|
||||
|
||||
private Member resolveMember() {
|
||||
ClassLoader loader = clazz.getClassLoader();
|
||||
Class<?>[] classes = new Class<?>[args.length];
|
||||
|
||||
// resolve args
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
classes[i] = ClassUtils.resolveClassName(args[i].getClassName(), loader);
|
||||
ClassLoader loader = this.clazz.getClassLoader();
|
||||
Class<?>[] argTypes = new Class<?>[this.args.length];
|
||||
for (int i = 0; i < this.args.length; i++) {
|
||||
argTypes[i] = ClassUtils.resolveClassName(this.args[i].getClassName(), loader);
|
||||
}
|
||||
try {
|
||||
if (CONSTRUCTOR.equals(name)) {
|
||||
return clazz.getDeclaredConstructor(classes);
|
||||
if (CONSTRUCTOR.equals(this.name)) {
|
||||
return this.clazz.getDeclaredConstructor(argTypes);
|
||||
}
|
||||
|
||||
return clazz.getDeclaredMethod(name, classes);
|
||||
} catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Method [" + name
|
||||
+ "] was discovered in the .class file but cannot be resolved in the class object", ex);
|
||||
return this.clazz.getDeclaredMethod(this.name, argTypes);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Method [" + this.name +
|
||||
"] was discovered in the .class file but cannot be resolved in the class object", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,7 +257,8 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
|
||||
lvtIndex[i] = nextIndex;
|
||||
if (isWideType(paramTypes[i])) {
|
||||
nextIndex += 2;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
nextIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,8 @@ public abstract class SpringProperties {
|
||||
static {
|
||||
try {
|
||||
ClassLoader cl = SpringProperties.class.getClassLoader();
|
||||
URL url = cl.getResource(PROPERTIES_RESOURCE_LOCATION);
|
||||
URL url = (cl != null ? cl.getResource(PROPERTIES_RESOURCE_LOCATION) :
|
||||
ClassLoader.getSystemResource(PROPERTIES_RESOURCE_LOCATION));
|
||||
if (url != null) {
|
||||
logger.info("Found 'spring.properties' file in local classpath");
|
||||
InputStream is = url.openStream();
|
||||
|
||||
+3
-11
@@ -58,7 +58,6 @@ public class AnnotatedElementUtils {
|
||||
|
||||
public static boolean hasMetaAnnotationTypes(AnnotatedElement element, String annotationType) {
|
||||
return Boolean.TRUE.equals(process(element, annotationType, false, new Processor<Boolean>() {
|
||||
|
||||
@Override
|
||||
public Boolean process(Annotation annotation, int metaDepth) {
|
||||
if (metaDepth > 0) {
|
||||
@@ -66,7 +65,6 @@ public class AnnotatedElementUtils {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcess(Annotation annotation, Boolean result) {
|
||||
}
|
||||
@@ -75,12 +73,10 @@ public class AnnotatedElementUtils {
|
||||
|
||||
public static boolean isAnnotated(AnnotatedElement element, String annotationType) {
|
||||
return Boolean.TRUE.equals(process(element, annotationType, false, new Processor<Boolean>() {
|
||||
|
||||
@Override
|
||||
public Boolean process(Annotation annotation, int metaDepth) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcess(Annotation annotation, Boolean result) {
|
||||
}
|
||||
@@ -95,12 +91,10 @@ public class AnnotatedElementUtils {
|
||||
final boolean classValuesAsString, final boolean nestedAnnotationsAsMap) {
|
||||
|
||||
return process(element, annotationType, false, new Processor<AnnotationAttributes>() {
|
||||
|
||||
@Override
|
||||
public AnnotationAttributes process(Annotation annotation, int metaDepth) {
|
||||
return AnnotationUtils.getAnnotationAttributes(annotation, classValuesAsString, nestedAnnotationsAsMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcess(Annotation annotation, AnnotationAttributes result) {
|
||||
for (String key : result.keySet()) {
|
||||
@@ -125,7 +119,6 @@ public class AnnotatedElementUtils {
|
||||
|
||||
final MultiValueMap<String, Object> attributes = new LinkedMultiValueMap<String, Object>();
|
||||
process(element, annotationType, false, new Processor<Void>() {
|
||||
|
||||
@Override
|
||||
public Void process(Annotation annotation, int metaDepth) {
|
||||
if (annotation.annotationType().getName().equals(annotationType)) {
|
||||
@@ -136,7 +129,6 @@ public class AnnotatedElementUtils {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcess(Annotation annotation, Void result) {
|
||||
for (String key : attributes.keySet()) {
|
||||
@@ -199,8 +191,8 @@ public class AnnotatedElementUtils {
|
||||
Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
|
||||
|
||||
if (visited.add(element)) {
|
||||
Annotation[] annotations = (traverseClassHierarchy ? element.getDeclaredAnnotations()
|
||||
: element.getAnnotations());
|
||||
Annotation[] annotations =
|
||||
(traverseClassHierarchy ? element.getDeclaredAnnotations() : element.getAnnotations());
|
||||
for (Annotation annotation : annotations) {
|
||||
if (annotation.annotationType().getName().equals(annotationType) || metaDepth > 0) {
|
||||
T result = processor.process(annotation, metaDepth);
|
||||
@@ -228,7 +220,7 @@ public class AnnotatedElementUtils {
|
||||
if (traverseClassHierarchy && element instanceof Class) {
|
||||
Class<?> superclass = ((Class<?>) element).getSuperclass();
|
||||
if (superclass != null && !superclass.equals(Object.class)) {
|
||||
T result = doProcess(superclass, annotationType, traverseClassHierarchy, processor, visited,
|
||||
T result = doProcess(superclass, annotationType, true, processor, visited,
|
||||
metaDepth);
|
||||
if (result != null) {
|
||||
return result;
|
||||
|
||||
+49
-58
@@ -70,8 +70,8 @@ public abstract class AnnotationUtils {
|
||||
* Get a single {@link Annotation} of {@code annotationType} from the supplied
|
||||
* annotation: either the given annotation itself or a meta-annotation thereof.
|
||||
* @param ann the Annotation to check
|
||||
* @param annotationType the annotation class to look for, both locally and as a meta-annotation
|
||||
* @return the matching annotation or {@code null} if not found
|
||||
* @param annotationType the annotation type to look for, both locally and as a meta-annotation
|
||||
* @return the matching annotation, or {@code null} if none found
|
||||
* @since 4.0
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -87,8 +87,8 @@ public abstract class AnnotationUtils {
|
||||
* Method, Constructor or Field. Meta-annotations will be searched if the annotation
|
||||
* is not declared locally on the supplied element.
|
||||
* @param ae the Method, Constructor or Field from which to get the annotation
|
||||
* @param annotationType the annotation class to look for, both locally and as a meta-annotation
|
||||
* @return the matching annotation or {@code null} if not found
|
||||
* @param annotationType the annotation type to look for, both locally and as a meta-annotation
|
||||
* @return the matching annotation, or {@code null} if none found
|
||||
* @since 3.1
|
||||
*/
|
||||
public static <T extends Annotation> T getAnnotation(AnnotatedElement ae, Class<T> annotationType) {
|
||||
@@ -119,7 +119,7 @@ public abstract class AnnotationUtils {
|
||||
* Get a single {@link Annotation} of {@code annotationType} from the supplied {@link Method}.
|
||||
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
|
||||
* @param method the method to look for annotations on
|
||||
* @param annotationType the annotation class to look for
|
||||
* @param annotationType the annotation type to look for
|
||||
* @return the annotations found
|
||||
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
|
||||
*/
|
||||
@@ -135,16 +135,16 @@ public abstract class AnnotationUtils {
|
||||
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
|
||||
* @param method the method to look for annotations on
|
||||
* @param containerAnnotationType the class of the container that holds the annotations
|
||||
* @param annotationType the annotation class to look for
|
||||
* @param annotationType the annotation type to look for
|
||||
* @return the annotations found
|
||||
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
|
||||
* @since 4.0
|
||||
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> getRepeatableAnnotation(Method method,
|
||||
Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) {
|
||||
|
||||
Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
return getRepeatableAnnotation((AnnotatedElement) resolvedMethod,
|
||||
containerAnnotationType, annotationType);
|
||||
return getRepeatableAnnotation((AnnotatedElement) resolvedMethod, containerAnnotationType, annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,13 +154,14 @@ public abstract class AnnotationUtils {
|
||||
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
|
||||
* @param annotatedElement the element to look for annotations on
|
||||
* @param containerAnnotationType the class of the container that holds the annotations
|
||||
* @param annotationType the annotation class to look for
|
||||
* @param annotationType the annotation type to look for
|
||||
* @return the annotations found
|
||||
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
|
||||
* @since 4.0
|
||||
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> getRepeatableAnnotation(AnnotatedElement annotatedElement,
|
||||
Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) {
|
||||
|
||||
if (annotatedElement.getAnnotations().length == 0) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
@@ -169,13 +170,13 @@ public abstract class AnnotationUtils {
|
||||
|
||||
/**
|
||||
* Find a single {@link Annotation} of {@code annotationType} from the supplied
|
||||
* {@link Method}, traversing its super methods (i.e., from super classes and
|
||||
* {@link Method}, traversing its super methods (i.e., from superclasses and
|
||||
* interfaces) if no annotation can be found on the given method itself.
|
||||
* <p>Annotations on methods are not inherited by default, so we need to handle
|
||||
* this explicitly.
|
||||
* @param method the method to look for annotations on
|
||||
* @param annotationType the annotation class to look for
|
||||
* @return the annotation found, or {@code null} if none found
|
||||
* @param annotationType the annotation type to look for
|
||||
* @return the annotation found, or {@code null} if none
|
||||
*/
|
||||
public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) {
|
||||
A annotation = getAnnotation(method, annotationType);
|
||||
@@ -274,10 +275,8 @@ public abstract class AnnotationUtils {
|
||||
* @param visited the set of annotations that have already been visited
|
||||
* @return the annotation if found, or {@code null} if not found
|
||||
*/
|
||||
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType,
|
||||
Set<Annotation> visited) {
|
||||
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
|
||||
if (isAnnotationDeclaredLocally(annotationType, clazz)) {
|
||||
return clazz.getAnnotation(annotationType);
|
||||
}
|
||||
@@ -289,8 +288,7 @@ public abstract class AnnotationUtils {
|
||||
}
|
||||
for (Annotation ann : clazz.getDeclaredAnnotations()) {
|
||||
if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
|
||||
A annotation = findAnnotation(ann.annotationType(), annotationType,
|
||||
visited);
|
||||
A annotation = findAnnotation(ann.annotationType(), annotationType, visited);
|
||||
if (annotation != null) {
|
||||
return annotation;
|
||||
}
|
||||
@@ -313,8 +311,8 @@ public abstract class AnnotationUtils {
|
||||
* <p>The standard {@link Class} API does not provide a mechanism for determining which class
|
||||
* in an inheritance hierarchy actually declares an {@link Annotation}, so we need to handle
|
||||
* this explicitly.
|
||||
* @param annotationType the annotation class to look for, both locally and as a meta-annotation
|
||||
* @param clazz the class on which to check for the annotation, or {@code null}
|
||||
* @param annotationType the annotation type to look for, both locally and as a meta-annotation
|
||||
* @param clazz the class on which to check for the annotation (may be {@code null})
|
||||
* @return the first {@link Class} in the inheritance hierarchy of the specified {@code clazz}
|
||||
* which declares an annotation for the specified {@code annotationType}, or {@code null}
|
||||
* if not found
|
||||
@@ -423,10 +421,9 @@ public abstract class AnnotationUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the supplied {@link Annotation} is defined in the
|
||||
* Determine if the supplied {@link Annotation} is defined in the core JDK
|
||||
* {@code java.lang.annotation} package.
|
||||
*
|
||||
* @param annotation the annotation to check; never {@code null}
|
||||
* @param annotation the annotation to check (never {@code null})
|
||||
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
|
||||
*/
|
||||
public static boolean isInJavaLangAnnotationPackage(Annotation annotation) {
|
||||
@@ -435,11 +432,10 @@ public abstract class AnnotationUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the given annotation's attributes as a Map, preserving all attribute types
|
||||
* as-is.
|
||||
* <p>Note: As of Spring 3.1.1, the returned map is actually an
|
||||
* {@link AnnotationAttributes} instance, however the Map signature of this method has
|
||||
* been preserved for binary compatibility.
|
||||
* Retrieve the given annotation's attributes as a {@link Map}, preserving all
|
||||
* attribute types as-is.
|
||||
* <p>Note: This method actually returns an {@link AnnotationAttributes} instance.
|
||||
* However, the {@code Map} signature has been preserved for binary compatibility.
|
||||
* @param annotation the annotation to retrieve the attributes for
|
||||
* @return the Map of annotation attributes, with attribute names as keys and
|
||||
* corresponding attribute values as values
|
||||
@@ -449,16 +445,15 @@ public abstract class AnnotationUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the given annotation's attributes as a Map. Equivalent to calling
|
||||
* {@link #getAnnotationAttributes(Annotation, boolean, boolean)} with
|
||||
* Retrieve the given annotation's attributes as a {@link Map}. Equivalent to
|
||||
* calling {@link #getAnnotationAttributes(Annotation, boolean, boolean)} with
|
||||
* the {@code nestedAnnotationsAsMap} parameter set to {@code false}.
|
||||
* <p>Note: As of Spring 3.1.1, the returned map is actually an
|
||||
* {@link AnnotationAttributes} instance, however the Map signature of this method has
|
||||
* been preserved for binary compatibility.
|
||||
* <p>Note: This method actually returns an {@link AnnotationAttributes} instance.
|
||||
* However, the {@code Map} signature has been preserved for binary compatibility.
|
||||
* @param annotation the annotation to retrieve the attributes for
|
||||
* @param classValuesAsString whether to turn Class references into Strings (for
|
||||
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
|
||||
* preserve them as Class references
|
||||
* compatibility with {@link org.springframework.core.type.AnnotationMetadata}
|
||||
* or to preserve them as Class references
|
||||
* @return the Map of annotation attributes, with attribute names as keys and
|
||||
* corresponding attribute values as values
|
||||
*/
|
||||
@@ -468,13 +463,13 @@ public abstract class AnnotationUtils {
|
||||
|
||||
/**
|
||||
* Retrieve the given annotation's attributes as an {@link AnnotationAttributes}
|
||||
* map structure. Implemented in Spring 3.1.1 to provide fully recursive annotation
|
||||
* reading capabilities on par with that of the reflection-based
|
||||
* {@link org.springframework.core.type.StandardAnnotationMetadata}.
|
||||
* map structure.
|
||||
* <p>This method provides fully recursive annotation reading capabilities on par with
|
||||
* the reflection-based {@link org.springframework.core.type.StandardAnnotationMetadata}.
|
||||
* @param annotation the annotation to retrieve the attributes for
|
||||
* @param classValuesAsString whether to turn Class references into Strings (for
|
||||
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
|
||||
* preserve them as Class references
|
||||
* compatibility with {@link org.springframework.core.type.AnnotationMetadata}
|
||||
* or to preserve them as Class references
|
||||
* @param nestedAnnotationsAsMap whether to turn nested Annotation instances into
|
||||
* {@link AnnotationAttributes} maps (for compatibility with
|
||||
* {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as
|
||||
@@ -507,14 +502,13 @@ public abstract class AnnotationUtils {
|
||||
}
|
||||
if (nestedAnnotationsAsMap && value instanceof Annotation) {
|
||||
attrs.put(method.getName(),
|
||||
getAnnotationAttributes((Annotation) value, classValuesAsString, nestedAnnotationsAsMap));
|
||||
getAnnotationAttributes((Annotation) value, classValuesAsString, true));
|
||||
}
|
||||
else if (nestedAnnotationsAsMap && value instanceof Annotation[]) {
|
||||
Annotation[] realAnnotations = (Annotation[]) value;
|
||||
AnnotationAttributes[] mappedAnnotations = new AnnotationAttributes[realAnnotations.length];
|
||||
for (int i = 0; i < realAnnotations.length; i++) {
|
||||
mappedAnnotations[i] = getAnnotationAttributes(
|
||||
realAnnotations[i], classValuesAsString, nestedAnnotationsAsMap);
|
||||
mappedAnnotations[i] = getAnnotationAttributes(realAnnotations[i], classValuesAsString, true);
|
||||
}
|
||||
attrs.put(method.getName(), mappedAnnotations);
|
||||
}
|
||||
@@ -542,7 +536,7 @@ public abstract class AnnotationUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the <em>value</em> of a named Annotation attribute, given an annotation instance.
|
||||
* Retrieve the <em>value</em> of a named attribute, given an annotation instance.
|
||||
* @param annotation the annotation instance from which to retrieve the value
|
||||
* @param attributeName the name of the attribute value to retrieve
|
||||
* @return the attribute value, or {@code null} if not found
|
||||
@@ -550,7 +544,7 @@ public abstract class AnnotationUtils {
|
||||
*/
|
||||
public static Object getValue(Annotation annotation, String attributeName) {
|
||||
try {
|
||||
Method method = annotation.annotationType().getDeclaredMethod(attributeName, new Class<?>[0]);
|
||||
Method method = annotation.annotationType().getDeclaredMethod(attributeName);
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
return method.invoke(annotation);
|
||||
}
|
||||
@@ -571,7 +565,7 @@ public abstract class AnnotationUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the <em>default value</em> of a named Annotation attribute, given an annotation instance.
|
||||
* Retrieve the <em>default value</em> of a named attribute, given an annotation instance.
|
||||
* @param annotation the annotation instance from which to retrieve the default value
|
||||
* @param attributeName the name of the attribute value to retrieve
|
||||
* @return the default value of the named attribute, or {@code null} if not found
|
||||
@@ -593,7 +587,8 @@ public abstract class AnnotationUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the <em>default value</em> of a named Annotation attribute, given the {@link Class annotation type}.
|
||||
* Retrieve the <em>default value</em> of a named attribute, given the
|
||||
* {@link Class annotation type}.
|
||||
* @param annotationType the <em>annotation type</em> for which the default value should be retrieved
|
||||
* @param attributeName the name of the attribute value to retrieve.
|
||||
* @return the default value of the named attribute, or {@code null} if not found
|
||||
@@ -601,8 +596,7 @@ public abstract class AnnotationUtils {
|
||||
*/
|
||||
public static Object getDefaultValue(Class<? extends Annotation> annotationType, String attributeName) {
|
||||
try {
|
||||
Method method = annotationType.getDeclaredMethod(attributeName, new Class<?>[0]);
|
||||
return method.getDefaultValue();
|
||||
return annotationType.getDeclaredMethod(attributeName).getDefaultValue();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
@@ -620,14 +614,11 @@ public abstract class AnnotationUtils {
|
||||
|
||||
private final Set<A> result = new LinkedHashSet<A>();
|
||||
|
||||
|
||||
public AnnotationCollector(Class<? extends Annotation> containerAnnotationType,
|
||||
Class<A> annotationType) {
|
||||
public AnnotationCollector(Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) {
|
||||
this.containerAnnotationType = containerAnnotationType;
|
||||
this.annotationType = annotationType;
|
||||
}
|
||||
|
||||
|
||||
public Set<A> getResult(AnnotatedElement element) {
|
||||
process(element);
|
||||
return Collections.unmodifiableSet(this.result);
|
||||
@@ -641,7 +632,7 @@ public abstract class AnnotationUtils {
|
||||
this.result.add((A) annotation);
|
||||
}
|
||||
else if (ObjectUtils.nullSafeEquals(this.containerAnnotationType, annotation.annotationType())) {
|
||||
result.addAll(Arrays.asList(getValue(annotation)));
|
||||
this.result.addAll(Arrays.asList(getValue(annotation)));
|
||||
}
|
||||
else if (!isInJavaLangAnnotationPackage(annotation)) {
|
||||
process(annotation.annotationType());
|
||||
@@ -658,10 +649,10 @@ public abstract class AnnotationUtils {
|
||||
return (A[]) method.invoke(annotation);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Unable to read value from repeating annotation container "
|
||||
+ this.containerAnnotationType.getName(), ex);
|
||||
throw new IllegalStateException("Unable to read value from repeating annotation container " +
|
||||
this.containerAnnotationType.getName(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,6 +20,7 @@ import org.springframework.core.convert.converter.Converter;
|
||||
|
||||
/**
|
||||
* Simply calls {@link Object#toString()} to convert a source Object to a String.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,12 +29,11 @@ import java.util.Set;
|
||||
*/
|
||||
public class CompositePropertySource extends PropertySource<Object> {
|
||||
|
||||
private Set<PropertySource<?>> propertySources = new LinkedHashSet<PropertySource<?>>();
|
||||
private final Set<PropertySource<?>> propertySources = new LinkedHashSet<PropertySource<?>>();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code CompositePropertySource}.
|
||||
*
|
||||
* @param name the name of the property source
|
||||
*/
|
||||
public CompositePropertySource(String name) {
|
||||
@@ -60,6 +59,7 @@ public class CompositePropertySource extends PropertySource<Object> {
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s [name='%s', propertySources=%s]",
|
||||
this.getClass().getSimpleName(), this.name, this.propertySources);
|
||||
getClass().getSimpleName(), this.name, this.propertySources);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,6 +18,7 @@ package org.springframework.core.env;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -53,22 +54,23 @@ public abstract class EnumerablePropertySource<T> extends PropertySource<T> {
|
||||
super(name, source);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the names of all properties contained by the {@linkplain #getSource()
|
||||
* source} object (never {@code null}).
|
||||
* Return the names of all properties contained by the
|
||||
* {@linkplain #getSource() source} object (never {@code null}).
|
||||
*/
|
||||
public abstract String[] getPropertyNames();
|
||||
|
||||
/**
|
||||
* Return whether this {@code PropertySource} contains a property with the given name.
|
||||
* <p>This implementation checks for the presence of the given name within
|
||||
* the {@link #getPropertyNames()} array.
|
||||
* @param name the property to find
|
||||
* <p>This implementation checks for the presence of the given name within the
|
||||
* {@link #getPropertyNames()} array.
|
||||
* @param name the name of the property to find
|
||||
*/
|
||||
@Override
|
||||
public boolean containsProperty(String name) {
|
||||
Assert.notNull(name, "property name must not be null");
|
||||
for (String candidate : this.getPropertyNames()) {
|
||||
Assert.notNull(name, "Property name must not be null");
|
||||
for (String candidate : getPropertyNames()) {
|
||||
if (candidate.equals(name)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("PropertySource [%s] contains '%s'", getName(), name));
|
||||
|
||||
+7
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,13 +30,18 @@ import java.util.Properties;
|
||||
* {@link Properties#getProperty} and {@link Properties#setProperty}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class PropertiesPropertySource extends MapPropertySource {
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public PropertiesPropertySource(String name, Properties source) {
|
||||
super(name, (Map) source);
|
||||
}
|
||||
|
||||
protected PropertiesPropertySource(String name, Map<String, Object> source) {
|
||||
super(name, source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+37
-54
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,7 +18,9 @@ package org.springframework.core.env;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Abstract base class representing a source of name/value property pairs. The underlying
|
||||
@@ -55,12 +57,13 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public abstract class PropertySource<T> {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected final String name;
|
||||
|
||||
protected final T source;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code PropertySource} with the given name and source object.
|
||||
*/
|
||||
@@ -74,15 +77,15 @@ public abstract class PropertySource<T> {
|
||||
/**
|
||||
* Create a new {@code PropertySource} with the given name and with a new {@code Object}
|
||||
* instance as the underlying source.
|
||||
* <p>Often useful in testing scenarios when creating
|
||||
* anonymous implementations that never query an actual source, but rather return
|
||||
* hard-coded values.
|
||||
* <p>Often useful in testing scenarios when creating anonymous implementations that
|
||||
* never query an actual source but rather return hard-coded values.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public PropertySource(String name) {
|
||||
this(name, (T) new Object());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the name of this {@code PropertySource}
|
||||
*/
|
||||
@@ -94,91 +97,75 @@ public abstract class PropertySource<T> {
|
||||
* Return the underlying source object for this {@code PropertySource}.
|
||||
*/
|
||||
public T getSource() {
|
||||
return source;
|
||||
return this.source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this {@code PropertySource} contains the given name.
|
||||
* <p>This implementation simply checks for a null return value
|
||||
* from {@link #getProperty(String)}. Subclasses may wish to
|
||||
* implement a more efficient algorithm if possible.
|
||||
* <p>This implementation simply checks for a {@code null} return value
|
||||
* from {@link #getProperty(String)}. Subclasses may wish to implement
|
||||
* a more efficient algorithm if possible.
|
||||
* @param name the property name to find
|
||||
*/
|
||||
public boolean containsProperty(String name) {
|
||||
return this.getProperty(name) != null;
|
||||
return (getProperty(name) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value associated with the given name, {@code null} if not found.
|
||||
* Return the value associated with the given name,
|
||||
* or {@code null} if not found.
|
||||
* @param name the property to find
|
||||
* @see PropertyResolver#getRequiredProperty(String)
|
||||
*/
|
||||
public abstract Object getProperty(String name);
|
||||
|
||||
/**
|
||||
* Return a hashcode derived from the {@code name} property of this {@code PropertySource}
|
||||
* object.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This {@code PropertySource} object is equal to the given object if:
|
||||
* <ul>
|
||||
* <li>they are the same instance
|
||||
* <li>the {@code name} properties for both objects are equal
|
||||
* <li>they are the same instance
|
||||
* <li>the {@code name} properties for both objects are equal
|
||||
* </ul>
|
||||
*
|
||||
* <P>No properties other than {@code name} are evaluated.
|
||||
* <p>No properties other than {@code name} are evaluated.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (!(obj instanceof PropertySource))
|
||||
return false;
|
||||
PropertySource<?> other = (PropertySource<?>) obj;
|
||||
if (this.name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!this.name.equals(other.name))
|
||||
return false;
|
||||
return true;
|
||||
return (this == obj || (obj instanceof PropertySource &&
|
||||
ObjectUtils.nullSafeEquals(this.name, ((PropertySource<?>) obj).name)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash code derived from the {@code name} property
|
||||
* of this {@code PropertySource} object.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce concise output (type and name) if the current log level does not include
|
||||
* debug. If debug is enabled, produce verbose output including hashcode of the
|
||||
* debug. If debug is enabled, produce verbose output including the hash code of the
|
||||
* PropertySource instance and every name/value property pair.
|
||||
*
|
||||
* This variable verbosity is useful as a property source such as system properties
|
||||
* <p>This variable verbosity is useful as a property source such as system properties
|
||||
* or environment variables may contain an arbitrary number of property pairs,
|
||||
* potentially leading to difficult to read exception and log messages.
|
||||
*
|
||||
* @see Log#isDebugEnabled()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
return String.format("%s@%s [name='%s', properties=%s]",
|
||||
this.getClass().getSimpleName(), System.identityHashCode(this), this.name, this.source);
|
||||
getClass().getSimpleName(), System.identityHashCode(this), this.name, this.source);
|
||||
}
|
||||
else {
|
||||
return String.format("%s [name='%s']", getClass().getSimpleName(), this.name);
|
||||
}
|
||||
|
||||
return String.format("%s [name='%s']",
|
||||
this.getClass().getSimpleName(), this.name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a {@code PropertySource} implementation intended for collection comparison purposes only.
|
||||
*
|
||||
* <p>Primarily for internal use, but given a collection of {@code PropertySource} objects, may be
|
||||
* used as follows:
|
||||
* <pre class="code">
|
||||
@@ -189,11 +176,9 @@ public abstract class PropertySource<T> {
|
||||
* assert sources.contains(PropertySource.named("sourceB"));
|
||||
* assert !sources.contains(PropertySource.named("sourceC"));
|
||||
* }</pre>
|
||||
*
|
||||
* The returned {@code PropertySource} will throw {@code UnsupportedOperationException}
|
||||
* if any methods other than {@code equals(Object)}, {@code hashCode()}, and {@code toString()}
|
||||
* are called.
|
||||
*
|
||||
* @param name the name of the comparison {@code PropertySource} to be created and returned.
|
||||
*/
|
||||
public static PropertySource<?> named(String name) {
|
||||
@@ -209,7 +194,6 @@ public abstract class PropertySource<T> {
|
||||
* {@code ApplicationContext}. In such cases, a stub should be used to hold the
|
||||
* intended default position/order of the property source, then be replaced
|
||||
* during context refresh.
|
||||
*
|
||||
* @see org.springframework.context.support.AbstractApplicationContext#initPropertySources()
|
||||
* @see org.springframework.web.context.support.StandardServletEnvironment
|
||||
* @see org.springframework.web.context.support.ServletContextPropertySource
|
||||
@@ -221,7 +205,7 @@ public abstract class PropertySource<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Always return {@code null}.
|
||||
* Always returns {@code null}.
|
||||
*/
|
||||
@Override
|
||||
public String getProperty(String name) {
|
||||
@@ -236,8 +220,7 @@ public abstract class PropertySource<T> {
|
||||
static class ComparisonPropertySource extends StubPropertySource {
|
||||
|
||||
private static final String USAGE_ERROR =
|
||||
"ComparisonPropertySource instances are for collection comparison " +
|
||||
"use only";
|
||||
"ComparisonPropertySource instances are for use with collection comparison only";
|
||||
|
||||
public ComparisonPropertySource(String name) {
|
||||
super(name);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,9 +50,9 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ClassPathResource for ClassLoader usage.
|
||||
* A leading slash will be removed, as the ClassLoader
|
||||
* resource access methods will not accept it.
|
||||
* Create a new {@code ClassPathResource} for {@code ClassLoader} usage.
|
||||
* A leading slash will be removed, as the ClassLoader resource access
|
||||
* methods will not accept it.
|
||||
* <p>The thread context class loader will be used for
|
||||
* loading the resource.
|
||||
* @param path the absolute path within the class path
|
||||
@@ -64,9 +64,9 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ClassPathResource for ClassLoader usage.
|
||||
* A leading slash will be removed, as the ClassLoader
|
||||
* resource access methods will not accept it.
|
||||
* Create a new {@code ClassPathResource} for {@code ClassLoader} usage.
|
||||
* A leading slash will be removed, as the ClassLoader resource access
|
||||
* methods will not accept it.
|
||||
* @param path the absolute path within the classpath
|
||||
* @param classLoader the class loader to load the resource with,
|
||||
* or {@code null} for the thread context class loader
|
||||
@@ -83,9 +83,9 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ClassPathResource for Class usage.
|
||||
* The path can be relative to the given class,
|
||||
* or absolute within the classpath via a leading slash.
|
||||
* Create a new {@code ClassPathResource} for {@code Class} usage.
|
||||
* The path can be relative to the given class, or absolute within
|
||||
* the classpath via a leading slash.
|
||||
* @param path relative or absolute path within the class path
|
||||
* @param clazz the class to load resources with
|
||||
* @see java.lang.Class#getResourceAsStream
|
||||
@@ -97,8 +97,8 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ClassPathResource with optional ClassLoader and Class.
|
||||
* Only for internal usage.
|
||||
* Create a new {@code ClassPathResource} with optional {@code ClassLoader}
|
||||
* and {@code Class}. Only for internal usage.
|
||||
* @param path relative or absolute path within the classpath
|
||||
* @param classLoader the class loader to load the resource with, if any
|
||||
* @param clazz the class to load resources with, if any
|
||||
@@ -109,6 +109,7 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the path for this resource (as resource path within the class path).
|
||||
*/
|
||||
@@ -120,9 +121,10 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
* Return the ClassLoader that this resource will be obtained from.
|
||||
*/
|
||||
public final ClassLoader getClassLoader() {
|
||||
return (this.classLoader != null ? this.classLoader : this.clazz.getClassLoader());
|
||||
return (this.clazz != null ? this.clazz.getClassLoader() : this.classLoader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation checks for the resolution of a resource URL.
|
||||
* @see java.lang.ClassLoader#getResource(String)
|
||||
@@ -130,14 +132,23 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
*/
|
||||
@Override
|
||||
public boolean exists() {
|
||||
URL url;
|
||||
return (resolveURL() != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a URL for the underlying class path resource.
|
||||
* @return the resolved URL, or {@code null} if not resolvable
|
||||
*/
|
||||
protected URL resolveURL() {
|
||||
if (this.clazz != null) {
|
||||
url = this.clazz.getResource(this.path);
|
||||
return this.clazz.getResource(this.path);
|
||||
}
|
||||
else if (this.classLoader != null) {
|
||||
return this.classLoader.getResource(this.path);
|
||||
}
|
||||
else {
|
||||
url = this.classLoader.getResource(this.path);
|
||||
return ClassLoader.getSystemResource(this.path);
|
||||
}
|
||||
return (url != null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,9 +162,12 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
if (this.clazz != null) {
|
||||
is = this.clazz.getResourceAsStream(this.path);
|
||||
}
|
||||
else {
|
||||
else if (this.classLoader != null) {
|
||||
is = this.classLoader.getResourceAsStream(this.path);
|
||||
}
|
||||
else {
|
||||
is = ClassLoader.getSystemResourceAsStream(this.path);
|
||||
}
|
||||
if (is == null) {
|
||||
throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
|
||||
}
|
||||
@@ -161,19 +175,14 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns a URL for the underlying class path resource.
|
||||
* This implementation returns a URL for the underlying class path resource,
|
||||
* if available.
|
||||
* @see java.lang.ClassLoader#getResource(String)
|
||||
* @see java.lang.Class#getResource(String)
|
||||
*/
|
||||
@Override
|
||||
public URL getURL() throws IOException {
|
||||
URL url;
|
||||
if (this.clazz != null) {
|
||||
url = this.clazz.getResource(this.path);
|
||||
}
|
||||
else {
|
||||
url = this.classLoader.getResource(this.path);
|
||||
}
|
||||
URL url = resolveURL();
|
||||
if (url == null) {
|
||||
throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -45,7 +45,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
|
||||
|
||||
|
||||
/**
|
||||
* Create a new FileSystemResource from a File handle.
|
||||
* Create a new {@code FileSystemResource} from a {@link File} handle.
|
||||
* <p>Note: When building relative resources via {@link #createRelative},
|
||||
* the relative path will apply <i>at the same directory level</i>:
|
||||
* e.g. new File("C:/dir1"), relative path "dir2" -> "C:/dir2"!
|
||||
@@ -62,7 +62,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new FileSystemResource from a file path.
|
||||
* Create a new {@code FileSystemResource} from a file path.
|
||||
* <p>Note: When building relative resources via {@link #createRelative},
|
||||
* it makes a difference whether the specified resource base path here
|
||||
* ends with a slash or not. In the case of "C:/dir1/", relative paths
|
||||
@@ -77,6 +77,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
|
||||
this.path = StringUtils.cleanPath(path);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the file path for this resource.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -70,7 +70,9 @@ public interface ResourceLoader {
|
||||
* <p>Clients which need to access the ClassLoader directly can do so
|
||||
* in a uniform manner with the ResourceLoader, rather than relying
|
||||
* on the thread context ClassLoader.
|
||||
* @return the ClassLoader (never {@code null})
|
||||
* @return the ClassLoader (only {@code null} if even the system
|
||||
* ClassLoader isn't accessible)
|
||||
* @see org.springframework.util.ClassUtils#getDefaultClassLoader()
|
||||
*/
|
||||
ClassLoader getClassLoader();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,8 +26,11 @@ import org.springframework.core.NestedIOException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* VFS based {@link Resource} implementation.
|
||||
* Supports the corresponding VFS API versions on JBoss AS 5.x as well as 6.x and 7.x.
|
||||
* JBoss VFS based {@link Resource} implementation.
|
||||
*
|
||||
* <p>As of Spring 4.0, this class supports VFS 3.x on JBoss AS 6+ (package
|
||||
* {@code org.jboss.vfs}) and is in particular compatible with JBoss AS 7 and
|
||||
* WildFly 8.
|
||||
*
|
||||
* @author Ales Justin
|
||||
* @author Juergen Hoeller
|
||||
@@ -40,9 +43,9 @@ public class VfsResource extends AbstractResource {
|
||||
private final Object resource;
|
||||
|
||||
|
||||
public VfsResource(Object resources) {
|
||||
Assert.notNull(resources, "VirtualFile must not be null");
|
||||
this.resource = resources;
|
||||
public VfsResource(Object resource) {
|
||||
Assert.notNull(resource, "VirtualFile must not be null");
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,8 +29,10 @@ import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Utility for detecting and accessing JBoss VFS in the classpath.
|
||||
* As of Spring 4.0, supports VFS 3.x on JBoss AS 6+ (package {@code org.jboss.vfs})
|
||||
* and is in particular compatible with JBoss AS 7 and WildFly 8.
|
||||
*
|
||||
* <p>As of Spring 4.0, this class supports VFS 3.x on JBoss AS 6+ (package
|
||||
* {@code org.jboss.vfs}) and is in particular compatible with JBoss AS 7 and
|
||||
* WildFly 8.
|
||||
*
|
||||
* <p>Thanks go to Marius Bogoevici for the initial patch.
|
||||
* <b>Note:</b> This is an internal class and should not be used outside the framework.
|
||||
|
||||
+26
-23
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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.core.io.UrlResource;
|
||||
import org.springframework.core.io.VfsResource;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
@@ -143,11 +144,15 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* <p><b>WARNING:</b> Ant-style patterns with "classpath:" resources are not
|
||||
* guaranteed to find matching resources if the root package to search is available
|
||||
* in multiple class path locations. This is because a resource such as<pre class="code">
|
||||
* in multiple class path locations. This is because a resource such as
|
||||
* <pre class="code">
|
||||
* com/mycompany/package1/service-context.xml
|
||||
* </pre>may be in only one location, but when a path such as<pre class="code">
|
||||
* </pre>
|
||||
* may be in only one location, but when a path such as
|
||||
* <pre class="code">
|
||||
* classpath:com/mycompany/**/service-context.xml
|
||||
* </pre>is used to try to resolve it, the resolver will work off the (first) URL
|
||||
* </pre>
|
||||
* is used to try to resolve it, the resolver will work off the (first) URL
|
||||
* returned by {@code getResource("com/mycompany");}. If this base package
|
||||
* node exists in multiple classloader locations, the actual end resource may
|
||||
* not be underneath. Therefore, preferably, use "{@code classpath*:}" with the same
|
||||
@@ -171,10 +176,10 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
|
||||
private static Method equinoxResolveMethod;
|
||||
|
||||
static {
|
||||
// Detect Equinox OSGi (e.g. on WebSphere 6.1)
|
||||
try {
|
||||
Class<?> fileLocatorClass = PathMatchingResourcePatternResolver.class.getClassLoader().loadClass(
|
||||
"org.eclipse.core.runtime.FileLocator");
|
||||
// Detect Equinox OSGi (e.g. on WebSphere 6.1)
|
||||
Class<?> fileLocatorClass = ClassUtils.forName("org.eclipse.core.runtime.FileLocator",
|
||||
PathMatchingResourcePatternResolver.class.getClassLoader());
|
||||
equinoxResolveMethod = fileLocatorClass.getMethod("resolve", URL.class);
|
||||
logger.debug("Found Equinox FileLocator for OSGi bundle URL resolution");
|
||||
}
|
||||
@@ -198,17 +203,6 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
|
||||
this.resourceLoader = new DefaultResourceLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new PathMatchingResourcePatternResolver with a DefaultResourceLoader.
|
||||
* @param classLoader the ClassLoader to load classpath resources with,
|
||||
* or {@code null} for using the thread context class loader
|
||||
* at the time of actual resource access
|
||||
* @see org.springframework.core.io.DefaultResourceLoader
|
||||
*/
|
||||
public PathMatchingResourcePatternResolver(ClassLoader classLoader) {
|
||||
this.resourceLoader = new DefaultResourceLoader(classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new PathMatchingResourcePatternResolver.
|
||||
* <p>ClassLoader access will happen via the thread context class loader.
|
||||
@@ -220,6 +214,18 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new PathMatchingResourcePatternResolver with a DefaultResourceLoader.
|
||||
* @param classLoader the ClassLoader to load classpath resources with,
|
||||
* or {@code null} for using the thread context class loader
|
||||
* at the time of actual resource access
|
||||
* @see org.springframework.core.io.DefaultResourceLoader
|
||||
*/
|
||||
public PathMatchingResourcePatternResolver(ClassLoader classLoader) {
|
||||
this.resourceLoader = new DefaultResourceLoader(classLoader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the ResourceLoader that this pattern resolver works with.
|
||||
*/
|
||||
@@ -227,10 +233,6 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
|
||||
return this.resourceLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ClassLoader that this pattern resolver works with
|
||||
* (never {@code null}).
|
||||
*/
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return getResourceLoader().getClassLoader();
|
||||
@@ -301,7 +303,8 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
|
||||
if (path.startsWith("/")) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
Enumeration<URL> resourceUrls = getClassLoader().getResources(path);
|
||||
ClassLoader cl = getClassLoader();
|
||||
Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path));
|
||||
Set<Resource> result = new LinkedHashSet<Resource>(16);
|
||||
while (resourceUrls.hasMoreElements()) {
|
||||
URL url = resourceUrls.nextElement();
|
||||
|
||||
+6
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,12 +170,13 @@ public abstract class PropertiesLoaderUtils {
|
||||
*/
|
||||
public static Properties loadAllProperties(String resourceName, ClassLoader classLoader) throws IOException {
|
||||
Assert.notNull(resourceName, "Resource name must not be null");
|
||||
ClassLoader clToUse = classLoader;
|
||||
if (clToUse == null) {
|
||||
clToUse = ClassUtils.getDefaultClassLoader();
|
||||
ClassLoader classLoaderToUse = classLoader;
|
||||
if (classLoaderToUse == null) {
|
||||
classLoaderToUse = ClassUtils.getDefaultClassLoader();
|
||||
}
|
||||
Enumeration<URL> urls = (classLoaderToUse != null ? classLoaderToUse.getResources(resourceName) :
|
||||
ClassLoader.getSystemResources(resourceName));
|
||||
Properties props = new Properties();
|
||||
Enumeration<URL> urls = clToUse.getResources(resourceName);
|
||||
while (urls.hasMoreElements()) {
|
||||
URL url = urls.nextElement();
|
||||
URLConnection con = url.openConnection();
|
||||
|
||||
+23
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
@@ -36,6 +37,8 @@ import org.springframework.util.StringUtils;
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see org.springframework.core.io.Resource
|
||||
* @see org.springframework.core.io.support.EncodedResource
|
||||
*/
|
||||
public class ResourcePropertySource extends PropertiesPropertySource {
|
||||
|
||||
@@ -112,10 +115,27 @@ public class ResourcePropertySource extends PropertiesPropertySource {
|
||||
this(new DefaultResourceLoader().getResource(location));
|
||||
}
|
||||
|
||||
private ResourcePropertySource(String name, Map<String, Object> source) {
|
||||
super(name, source);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the description string for the resource, and if empty returns
|
||||
* the class name of the resource plus its identity hash code.
|
||||
* Return a potentially adapted variant of this {@link ResourcePropertySource},
|
||||
* overriding the previously given (or derived) name with the specified name.
|
||||
*/
|
||||
public ResourcePropertySource withName(String name) {
|
||||
if (this.name.equals(name)) {
|
||||
return this;
|
||||
}
|
||||
return new ResourcePropertySource(name, this.source);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the description String for the given Resource; it the description is
|
||||
* empty, return the class name of the resource plus its identity hash code.
|
||||
* @see org.springframework.core.io.Resource#getDescription()
|
||||
*/
|
||||
private static String getNameForResource(Resource resource) {
|
||||
String name = resource.getDescription();
|
||||
|
||||
+8
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -67,16 +67,17 @@ public abstract class SpringFactoriesLoader {
|
||||
*/
|
||||
public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
|
||||
Assert.notNull(factoryClass, "'factoryClass' must not be null");
|
||||
if (classLoader == null) {
|
||||
classLoader = SpringFactoriesLoader.class.getClassLoader();
|
||||
ClassLoader classLoaderToUse = classLoader;
|
||||
if (classLoaderToUse == null) {
|
||||
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
|
||||
}
|
||||
List<String> factoryNames = loadFactoryNames(factoryClass, classLoader);
|
||||
List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames);
|
||||
}
|
||||
List<T> result = new ArrayList<T>(factoryNames.size());
|
||||
for (String factoryName : factoryNames) {
|
||||
result.add(instantiateFactory(factoryName, factoryClass, classLoader));
|
||||
result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));
|
||||
}
|
||||
OrderComparator.sort(result);
|
||||
return result;
|
||||
@@ -85,8 +86,9 @@ public abstract class SpringFactoriesLoader {
|
||||
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
|
||||
String factoryClassName = factoryClass.getName();
|
||||
try {
|
||||
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
|
||||
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
|
||||
List<String> result = new ArrayList<String>();
|
||||
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
|
||||
while (urls.hasMoreElements()) {
|
||||
URL url = urls.nextElement();
|
||||
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -128,7 +128,7 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
|
||||
public boolean hasAnnotatedMethods(String annotationType) {
|
||||
Method[] methods = getIntrospectedClass().getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
if (AnnotatedElementUtils.isAnnotated(method, annotationType)) {
|
||||
if (!method.isBridge() && AnnotatedElementUtils.isAnnotated(method, annotationType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,7 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
|
||||
Method[] methods = getIntrospectedClass().getDeclaredMethods();
|
||||
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
|
||||
for (Method method : methods) {
|
||||
if (AnnotatedElementUtils.isAnnotated(method, annotationType)) {
|
||||
if (!method.isBridge() && AnnotatedElementUtils.isAnnotated(method, annotationType)) {
|
||||
annotatedMethods.add(new StandardMethodMetadata(method, this.nestedAnnotationsAsMap));
|
||||
}
|
||||
}
|
||||
|
||||
+10
-5
@@ -25,6 +25,7 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.asm.AnnotationVisitor;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.asm.Opcodes;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
@@ -55,10 +56,9 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
|
||||
/**
|
||||
* Declared as a {@link LinkedMultiValueMap} instead of a {@link MultiValueMap}
|
||||
* to ensure that the hierarchical ordering of the entries is preserved.
|
||||
* @see AnnotationReadingVisitorUtils#getMergedAnnotationAttributes(LinkedMultiValueMap, String)
|
||||
* @see AnnotationReadingVisitorUtils#getMergedAnnotationAttributes
|
||||
*/
|
||||
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap = new LinkedMultiValueMap<String, AnnotationAttributes>(
|
||||
4);
|
||||
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap = new LinkedMultiValueMap<String, AnnotationAttributes>(4);
|
||||
|
||||
protected final Set<MethodMetadata> methodMetadataSet = new LinkedHashSet<MethodMetadata>(4);
|
||||
|
||||
@@ -70,6 +70,11 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
// Skip bridge methods - we're only interested in original annotation-defining user methods.
|
||||
// On JDK 8, we'd otherwise run into double detection of the same annotated method...
|
||||
if ((access & Opcodes.ACC_BRIDGE) != 0) {
|
||||
return super.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
return new MethodMetadataReadingVisitor(name, access, getClassName(), this.classLoader, this.methodMetadataSet);
|
||||
}
|
||||
|
||||
@@ -119,8 +124,8 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
|
||||
|
||||
@Override
|
||||
public AnnotationAttributes getAnnotationAttributes(String annotationType, boolean classValuesAsString) {
|
||||
AnnotationAttributes raw = AnnotationReadingVisitorUtils.getMergedAnnotationAttributes(this.attributesMap,
|
||||
annotationType);
|
||||
AnnotationAttributes raw = AnnotationReadingVisitorUtils.getMergedAnnotationAttributes(
|
||||
this.attributesMap, this.metaAnnotationMap, annotationType);
|
||||
return AnnotationReadingVisitorUtils.convertClassValues(this.classLoader, raw, classValuesAsString);
|
||||
}
|
||||
|
||||
|
||||
+31
-21
@@ -25,10 +25,9 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
|
||||
import static org.springframework.core.annotation.AnnotationUtils.VALUE;
|
||||
|
||||
/**
|
||||
* Internal utility class used when reading annotations.
|
||||
*
|
||||
@@ -98,20 +97,23 @@ abstract class AnnotationReadingVisitorUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the merged attributes of the annotation of the given type, if any,
|
||||
* from the supplied {@code attributesMap}.
|
||||
* Retrieve the merged attributes of the annotation of the given type,
|
||||
* if any, from the supplied {@code attributesMap}.
|
||||
* <p>Annotation attribute values appearing <em>lower</em> in the annotation
|
||||
* hierarchy (i.e., closer to the declaring class) will override those
|
||||
* defined <em>higher</em> in the annotation hierarchy.
|
||||
* @param attributesMap the map of annotation attribute lists, keyed by
|
||||
* annotation type name
|
||||
* @param attributesMap the map of annotation attribute lists,
|
||||
* keyed by annotation type name
|
||||
* @param metaAnnotationMap the map of meta annotation relationships,
|
||||
* keyed by annotation type name
|
||||
* @param annotationType the name of the annotation type to look for
|
||||
* @return the merged annotation attributes; or {@code null} if no matching
|
||||
* annotation is present in the {@code attributesMap}
|
||||
* @return the merged annotation attributes, or {@code null} if no
|
||||
* matching annotation is present in the {@code attributesMap}
|
||||
* @since 4.0.3
|
||||
*/
|
||||
public static AnnotationAttributes getMergedAnnotationAttributes(
|
||||
LinkedMultiValueMap<String, AnnotationAttributes> attributesMap, String annotationType) {
|
||||
LinkedMultiValueMap<String, AnnotationAttributes> attributesMap,
|
||||
Map<String, Set<String>> metaAnnotationMap, String annotationType) {
|
||||
|
||||
// Get the unmerged list of attributes for the target annotation.
|
||||
List<AnnotationAttributes> attributesList = attributesMap.get(annotationType);
|
||||
@@ -119,12 +121,14 @@ abstract class AnnotationReadingVisitorUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
// To start with, we populate the results with all attribute values from the
|
||||
// target annotation.
|
||||
AnnotationAttributes results = attributesList.get(0);
|
||||
// To start with, we populate the results with a copy of all attribute
|
||||
// values from the target annotation. A copy is necessary so that we do
|
||||
// not inadvertently mutate the state of the metadata passed to this
|
||||
// method.
|
||||
AnnotationAttributes results = new AnnotationAttributes(attributesList.get(0));
|
||||
|
||||
Set<String> overridableAttributeNames = new HashSet<String>(results.keySet());
|
||||
overridableAttributeNames.remove(VALUE);
|
||||
overridableAttributeNames.remove(AnnotationUtils.VALUE);
|
||||
|
||||
// Since the map is a LinkedMultiValueMap, we depend on the ordering of
|
||||
// elements in the map and reverse the order of the keys in order to traverse
|
||||
@@ -132,17 +136,23 @@ abstract class AnnotationReadingVisitorUtils {
|
||||
List<String> annotationTypes = new ArrayList<String>(attributesMap.keySet());
|
||||
Collections.reverse(annotationTypes);
|
||||
|
||||
// No need to revisit the target annotation type:
|
||||
annotationTypes.remove(annotationType);
|
||||
|
||||
for (String currentAnnotationType : annotationTypes) {
|
||||
List<AnnotationAttributes> currentAttributesList = attributesMap.get(currentAnnotationType);
|
||||
if (currentAttributesList != null && !currentAttributesList.isEmpty()) {
|
||||
AnnotationAttributes currentAttributes = currentAttributesList.get(0);
|
||||
for (String overridableAttributeName : overridableAttributeNames) {
|
||||
Object value = currentAttributes.get(overridableAttributeName);
|
||||
if (value != null) {
|
||||
// Store the value, potentially overriding a value from an
|
||||
// attribute of the same name found higher in the annotation
|
||||
// hierarchy.
|
||||
results.put(overridableAttributeName, value);
|
||||
Set<String> metaAnns = metaAnnotationMap.get(currentAnnotationType);
|
||||
if (metaAnns != null && metaAnns.contains(annotationType)) {
|
||||
AnnotationAttributes currentAttributes = currentAttributesList.get(0);
|
||||
for (String overridableAttributeName : overridableAttributeNames) {
|
||||
Object value = currentAttributes.get(overridableAttributeName);
|
||||
if (value != null) {
|
||||
// Store the value, potentially overriding a value from an
|
||||
// attribute of the same name found higher in the annotation
|
||||
// hierarchy.
|
||||
results.put(overridableAttributeName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+29
-31
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,8 +19,8 @@ package org.springframework.core.type.filter;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.core.type.ClassMetadata;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
|
||||
/**
|
||||
* Type filter that is aware of traversing over hierarchy.
|
||||
@@ -61,40 +61,38 @@ public abstract class AbstractTypeHierarchyTraversingFilter implements TypeFilte
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this.considerInherited) {
|
||||
return false;
|
||||
}
|
||||
if (metadata.hasSuperClass()) {
|
||||
// Optimization to avoid creating ClassReader for super class.
|
||||
Boolean superClassMatch = matchSuperClass(metadata.getSuperClassName());
|
||||
if (superClassMatch != null) {
|
||||
if (superClassMatch.booleanValue()) {
|
||||
return true;
|
||||
if (this.considerInherited) {
|
||||
if (metadata.hasSuperClass()) {
|
||||
// Optimization to avoid creating ClassReader for super class.
|
||||
Boolean superClassMatch = matchSuperClass(metadata.getSuperClassName());
|
||||
if (superClassMatch != null) {
|
||||
if (superClassMatch.booleanValue()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Need to read super class to determine a match...
|
||||
if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
|
||||
return true;
|
||||
else {
|
||||
// Need to read super class to determine a match...
|
||||
if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.considerInterfaces) {
|
||||
return false;
|
||||
}
|
||||
for (String ifc : metadata.getInterfaceNames()) {
|
||||
// Optimization to avoid creating ClassReader for super class
|
||||
Boolean interfaceMatch = matchInterface(ifc);
|
||||
if (interfaceMatch != null) {
|
||||
if (interfaceMatch.booleanValue()) {
|
||||
return true;
|
||||
if (this.considerInterfaces) {
|
||||
for (String ifc : metadata.getInterfaceNames()) {
|
||||
// Optimization to avoid creating ClassReader for super class
|
||||
Boolean interfaceMatch = matchInterface(ifc);
|
||||
if (interfaceMatch != null) {
|
||||
if (interfaceMatch.booleanValue()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Need to read interface to determine a match...
|
||||
if (match(ifc, metadataReaderFactory)) {
|
||||
return true;
|
||||
else {
|
||||
// Need to read interface to determine a match...
|
||||
if (match(ifc, metadataReaderFactory)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,7 +130,7 @@ public abstract class AbstractTypeHierarchyTraversingFilter implements TypeFilte
|
||||
/**
|
||||
* Override this to match on interface type name.
|
||||
*/
|
||||
protected Boolean matchInterface(String interfaceNames) {
|
||||
protected Boolean matchInterface(String interfaceName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+21
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,8 +19,10 @@ package org.springframework.core.type.filter;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Inherited;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* A simple filter which matches classes with a given annotation,
|
||||
@@ -49,7 +51,7 @@ public class AnnotationTypeFilter extends AbstractTypeHierarchyTraversingFilter
|
||||
* @param annotationType the annotation type to match
|
||||
*/
|
||||
public AnnotationTypeFilter(Class<? extends Annotation> annotationType) {
|
||||
this(annotationType, true);
|
||||
this(annotationType, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,16 +86,26 @@ public class AnnotationTypeFilter extends AbstractTypeHierarchyTraversingFilter
|
||||
|
||||
@Override
|
||||
protected Boolean matchSuperClass(String superClassName) {
|
||||
if (Object.class.getName().equals(superClassName)) {
|
||||
return Boolean.FALSE;
|
||||
return hasAnnotation(superClassName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean matchInterface(String interfaceName) {
|
||||
return hasAnnotation(interfaceName);
|
||||
}
|
||||
|
||||
protected Boolean hasAnnotation(String typeName) {
|
||||
if (Object.class.getName().equals(typeName)) {
|
||||
return false;
|
||||
}
|
||||
else if (superClassName.startsWith("java.")) {
|
||||
else if (typeName.startsWith("java")) {
|
||||
try {
|
||||
Class<?> clazz = getClass().getClassLoader().loadClass(superClassName);
|
||||
return (clazz.getAnnotation(this.annotationType) != null);
|
||||
Class<?> clazz = ClassUtils.forName(typeName, getClass().getClassLoader());
|
||||
return ((this.considerMetaAnnotations ? AnnotationUtils.getAnnotation(clazz, this.annotationType) :
|
||||
clazz.getAnnotation(this.annotationType)) != null);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Class not found - can't determine a match that way.
|
||||
catch (Throwable ex) {
|
||||
// Class not regularly loadable - can't determine a match that way.
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
+9
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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.core.type.filter;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* A simple filter which matches classes that are assignable to a given type.
|
||||
*
|
||||
@@ -59,15 +61,15 @@ public class AssignableTypeFilter extends AbstractTypeHierarchyTraversingFilter
|
||||
return true;
|
||||
}
|
||||
else if (Object.class.getName().equals(typeName)) {
|
||||
return Boolean.FALSE;
|
||||
return false;
|
||||
}
|
||||
else if (typeName.startsWith("java.")) {
|
||||
else if (typeName.startsWith("java")) {
|
||||
try {
|
||||
Class<?> clazz = getClass().getClassLoader().loadClass(typeName);
|
||||
return Boolean.valueOf(this.targetType.isAssignableFrom(clazz));
|
||||
Class<?> clazz = ClassUtils.forName(typeName, getClass().getClassLoader());
|
||||
return this.targetType.isAssignableFrom(clazz);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Class not found - can't determine a match that way.
|
||||
catch (Throwable ex) {
|
||||
// Class not regularly loadable - can't determine a match that way.
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -142,12 +142,14 @@ public abstract class ClassUtils {
|
||||
* ClassLoader, if available; the ClassLoader that loaded the ClassUtils
|
||||
* class will be used as fallback.
|
||||
* <p>Call this method if you intend to use the thread context ClassLoader
|
||||
* in a scenario where you absolutely need a non-null ClassLoader reference:
|
||||
* in a scenario where you clearly prefer a non-null ClassLoader reference:
|
||||
* for example, for class path resource loading (but not necessarily for
|
||||
* {@code Class.forName}, which accepts a {@code null} ClassLoader
|
||||
* reference as well).
|
||||
* @return the default ClassLoader (never {@code null})
|
||||
* @return the default ClassLoader (only {@code null} if even the system
|
||||
* ClassLoader isn't accessible)
|
||||
* @see Thread#getContextClassLoader()
|
||||
* @see ClassLoader#getSystemClassLoader()
|
||||
*/
|
||||
public static ClassLoader getDefaultClassLoader() {
|
||||
ClassLoader cl = null;
|
||||
@@ -155,11 +157,20 @@ public abstract class ClassUtils {
|
||||
cl = Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Cannot access thread context ClassLoader - falling back to system class loader...
|
||||
// Cannot access thread context ClassLoader - falling back...
|
||||
}
|
||||
if (cl == null) {
|
||||
// No thread context class loader -> use class loader of this class.
|
||||
cl = ClassUtils.class.getClassLoader();
|
||||
if (cl == null) {
|
||||
// getClassLoader() returning null indicates the bootstrap ClassLoader
|
||||
try {
|
||||
cl = ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
|
||||
}
|
||||
}
|
||||
}
|
||||
return cl;
|
||||
}
|
||||
@@ -185,7 +196,7 @@ public abstract class ClassUtils {
|
||||
|
||||
/**
|
||||
* Replacement for {@code Class.forName()} that also returns Class instances
|
||||
* for primitives (e.g."int") and array class names (e.g. "String[]").
|
||||
* for primitives (e.g. "int") and array class names (e.g. "String[]").
|
||||
* Furthermore, it is also capable of resolving inner class names in Java source
|
||||
* style (e.g. "java.lang.Thread.State" instead of "java.lang.Thread$State").
|
||||
* @param name the name of the Class
|
||||
@@ -228,19 +239,19 @@ public abstract class ClassUtils {
|
||||
return Array.newInstance(elementClass, 0).getClass();
|
||||
}
|
||||
|
||||
ClassLoader classLoaderToUse = classLoader;
|
||||
if (classLoaderToUse == null) {
|
||||
classLoaderToUse = getDefaultClassLoader();
|
||||
ClassLoader clToUse = classLoader;
|
||||
if (clToUse == null) {
|
||||
clToUse = getDefaultClassLoader();
|
||||
}
|
||||
try {
|
||||
return classLoaderToUse.loadClass(name);
|
||||
return (clToUse != null ? clToUse.loadClass(name) : Class.forName(name));
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
int lastDotIndex = name.lastIndexOf('.');
|
||||
if (lastDotIndex != -1) {
|
||||
String innerClassName = name.substring(0, lastDotIndex) + '$' + name.substring(lastDotIndex + 1);
|
||||
try {
|
||||
return classLoaderToUse.loadClass(innerClassName);
|
||||
return (clToUse != null ? clToUse.loadClass(innerClassName) : Class.forName(innerClassName));
|
||||
}
|
||||
catch (ClassNotFoundException ex2) {
|
||||
// swallow - let original exception get through
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -317,7 +317,7 @@ public abstract class CollectionUtils {
|
||||
* Enumeration elements must be assignable to the type of the given array. The array
|
||||
* returned will be a different instance than the array given.
|
||||
*/
|
||||
public static <A,E extends A> A[] toArray(Enumeration<E> enumeration, A[] array) {
|
||||
public static <A, E extends A> A[] toArray(Enumeration<E> enumeration, A[] array) {
|
||||
ArrayList<A> elements = new ArrayList<A>();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
elements.add(enumeration.nextElement());
|
||||
|
||||
@@ -387,7 +387,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
|
||||
protected static int calculateShift(int minimumValue, int maximumValue) {
|
||||
int shift = 0;
|
||||
int value = 1;
|
||||
while (value < minimumValue && value < minimumValue) {
|
||||
while (value < minimumValue && value < maximumValue) {
|
||||
value <<= 1;
|
||||
shift++;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -287,7 +287,7 @@ public class MimeType implements Comparable<MimeType>, Serializable {
|
||||
* method is <b>not</b> symmetric.
|
||||
* @param other the reference media type with which to compare
|
||||
* @return {@code true} if this media type includes the given media type;
|
||||
* {@code false} otherwise
|
||||
* {@code false} otherwise
|
||||
*/
|
||||
public boolean includes(MimeType other) {
|
||||
if (other == null) {
|
||||
@@ -424,7 +424,8 @@ public class MimeType implements Comparable<MimeType>, Serializable {
|
||||
return false;
|
||||
}
|
||||
MimeType otherType = (MimeType) other;
|
||||
return (this.type.equalsIgnoreCase(otherType.type) && this.subtype.equalsIgnoreCase(otherType.subtype) &&
|
||||
return (this.type.equalsIgnoreCase(otherType.type) &&
|
||||
this.subtype.equalsIgnoreCase(otherType.subtype) &&
|
||||
this.parameters.equals(otherType.parameters));
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ import java.io.ByteArrayOutputStream;
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
* @since 4.0.3
|
||||
*/
|
||||
public class ResizableByteArrayOutputStream extends ByteArrayOutputStream {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,15 +66,15 @@ public abstract class ResourceUtils {
|
||||
/** URL protocol for an entry from a zip file: "zip" */
|
||||
public static final String URL_PROTOCOL_ZIP = "zip";
|
||||
|
||||
/** URL protocol for an entry from a WebSphere jar file: "wsjar" */
|
||||
public static final String URL_PROTOCOL_WSJAR = "wsjar";
|
||||
|
||||
/** URL protocol for an entry from a JBoss jar file: "vfszip" */
|
||||
public static final String URL_PROTOCOL_VFSZIP = "vfszip";
|
||||
|
||||
/** URL protocol for a JBoss VFS resource: "vfs" */
|
||||
public static final String URL_PROTOCOL_VFS = "vfs";
|
||||
|
||||
/** URL protocol for an entry from a WebSphere jar file: "wsjar" */
|
||||
public static final String URL_PROTOCOL_WSJAR = "wsjar";
|
||||
|
||||
/** Separator between JAR URL and file path within the JAR */
|
||||
public static final String JAR_URL_SEPARATOR = "!/";
|
||||
|
||||
@@ -116,7 +116,8 @@ public abstract class ResourceUtils {
|
||||
Assert.notNull(resourceLocation, "Resource location must not be null");
|
||||
if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
|
||||
String path = resourceLocation.substring(CLASSPATH_URL_PREFIX.length());
|
||||
URL url = ClassUtils.getDefaultClassLoader().getResource(path);
|
||||
ClassLoader cl = ClassUtils.getDefaultClassLoader();
|
||||
URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));
|
||||
if (url == null) {
|
||||
String description = "class path resource [" + path + "]";
|
||||
throw new FileNotFoundException(
|
||||
@@ -156,7 +157,8 @@ public abstract class ResourceUtils {
|
||||
if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
|
||||
String path = resourceLocation.substring(CLASSPATH_URL_PREFIX.length());
|
||||
String description = "class path resource [" + path + "]";
|
||||
URL url = ClassUtils.getDefaultClassLoader().getResource(path);
|
||||
ClassLoader cl = ClassUtils.getDefaultClassLoader();
|
||||
URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));
|
||||
if (url == null) {
|
||||
throw new FileNotFoundException(
|
||||
description + " cannot be resolved to absolute file path " +
|
||||
@@ -252,7 +254,7 @@ public abstract class ResourceUtils {
|
||||
*/
|
||||
public static boolean isFileURL(URL url) {
|
||||
String protocol = url.getProtocol();
|
||||
return (URL_PROTOCOL_FILE.equals(protocol) || protocol.startsWith(URL_PROTOCOL_VFS));
|
||||
return (URL_PROTOCOL_FILE.equals(protocol) || URL_PROTOCOL_VFS.equals(protocol));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,8 +266,9 @@ public abstract class ResourceUtils {
|
||||
* @return whether the URL has been identified as a JAR URL
|
||||
*/
|
||||
public static boolean isJarURL(URL url) {
|
||||
String up = url.getProtocol();
|
||||
return (URL_PROTOCOL_JAR.equals(up) || URL_PROTOCOL_ZIP.equals(up) || URL_PROTOCOL_WSJAR.equals(up));
|
||||
String protocol = url.getProtocol();
|
||||
return (URL_PROTOCOL_JAR.equals(protocol) || URL_PROTOCOL_ZIP.equals(protocol) ||
|
||||
URL_PROTOCOL_WSJAR.equals(protocol) || URL_PROTOCOL_VFSZIP.equals(protocol));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
@@ -123,6 +124,63 @@ public class AnnotationMetadataTests {
|
||||
assertThat("length of basePackageClasses[]", basePackageClasses.length, is(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* https://jira.spring.io/browse/SPR-11649
|
||||
*/
|
||||
@Test
|
||||
public void multipleAnnotationsWithIdenticalAttributeNamesUsingStandardAnnotationMetadata() {
|
||||
AnnotationMetadata metadata = new StandardAnnotationMetadata(NamedAnnotationsClass.class);
|
||||
assertMultipleAnnotationsWithIdenticalAttributeNames(metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* https://jira.spring.io/browse/SPR-11649
|
||||
*/
|
||||
@Test
|
||||
public void multipleAnnotationsWithIdenticalAttributeNamesUsingAnnotationMetadataReadingVisitor() throws Exception {
|
||||
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
|
||||
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(NamedAnnotationsClass.class.getName());
|
||||
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
|
||||
assertMultipleAnnotationsWithIdenticalAttributeNames(metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* https://jira.spring.io/browse/SPR-11649
|
||||
*/
|
||||
@Test
|
||||
public void composedAnnotationWithMetaAnnotationsWithIdenticalAttributeNamesUsingStandardAnnotationMetadata() {
|
||||
AnnotationMetadata metadata = new StandardAnnotationMetadata(NamedComposedAnnotationClass.class);
|
||||
assertMultipleAnnotationsWithIdenticalAttributeNames(metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* https://jira.spring.io/browse/SPR-11649
|
||||
*/
|
||||
@Test
|
||||
public void composedAnnotationWithMetaAnnotationsWithIdenticalAttributeNamesUsingAnnotationMetadataReadingVisitor() throws Exception {
|
||||
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
|
||||
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(NamedComposedAnnotationClass.class.getName());
|
||||
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
|
||||
assertMultipleAnnotationsWithIdenticalAttributeNames(metadata);
|
||||
}
|
||||
|
||||
private void assertMultipleAnnotationsWithIdenticalAttributeNames(AnnotationMetadata metadata) {
|
||||
AnnotationAttributes attributes1 = (AnnotationAttributes) metadata.getAnnotationAttributes(
|
||||
NamedAnnotation1.class.getName(), false);
|
||||
String name1 = attributes1.getString("name");
|
||||
assertThat("name of NamedAnnotation1", name1, is("name 1"));
|
||||
|
||||
AnnotationAttributes attributes2 = (AnnotationAttributes) metadata.getAnnotationAttributes(
|
||||
NamedAnnotation2.class.getName(), false);
|
||||
String name2 = attributes2.getString("name");
|
||||
assertThat("name of NamedAnnotation2", name2, is("name 2"));
|
||||
|
||||
AnnotationAttributes attributes3 = (AnnotationAttributes) metadata.getAnnotationAttributes(
|
||||
NamedAnnotation3.class.getName(), false);
|
||||
String name3 = attributes3.getString("name");
|
||||
assertThat("name of NamedAnnotation3", name3, is("name 3"));
|
||||
}
|
||||
|
||||
private void doTestAnnotationInfo(AnnotationMetadata metadata) {
|
||||
assertThat(metadata.getClassName(), is(AnnotatedComponent.class.getName()));
|
||||
assertThat(metadata.isInterface(), is(false));
|
||||
@@ -318,8 +376,10 @@ public class AnnotationMetadataTests {
|
||||
// SPR-10914
|
||||
public static enum SubclassEnum {
|
||||
FOO {
|
||||
/* Do not delete! This subclassing is intentional. */
|
||||
},
|
||||
BAR {
|
||||
/* Do not delete! This subclassing is intentional. */
|
||||
};
|
||||
}
|
||||
|
||||
@@ -346,6 +406,7 @@ public class AnnotationMetadataTests {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "serial" })
|
||||
private static class AnnotatedComponentSubClass extends AnnotatedComponent {
|
||||
|
||||
}
|
||||
@@ -382,4 +443,40 @@ public class AnnotationMetadataTests {
|
||||
public static class ComposedConfigurationWithAttributeOverridesClass {
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public static @interface NamedAnnotation1 {
|
||||
String name() default "";
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public static @interface NamedAnnotation2 {
|
||||
String name() default "";
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public static @interface NamedAnnotation3 {
|
||||
String name() default "";
|
||||
}
|
||||
|
||||
@NamedAnnotation1(name = "name 1")
|
||||
@NamedAnnotation2(name = "name 2")
|
||||
@NamedAnnotation3(name = "name 3")
|
||||
public static class NamedAnnotationsClass {
|
||||
}
|
||||
|
||||
@NamedAnnotation1(name = "name 1")
|
||||
@NamedAnnotation2(name = "name 2")
|
||||
@NamedAnnotation3(name = "name 3")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public static @interface NamedComposedAnnotation {
|
||||
}
|
||||
|
||||
@NamedComposedAnnotation
|
||||
public static class NamedComposedAnnotationClass {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,22 +21,19 @@ import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
|
||||
/**
|
||||
* Implements equality operator.
|
||||
* Implements the equality operator.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class OpEQ extends Operator {
|
||||
|
||||
|
||||
public OpEQ(int pos, SpelNodeImpl... operands) {
|
||||
super("==", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state)
|
||||
throws EvaluationException {
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
return BooleanTypedValue.forValue(equalityCheck(state, left, right));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,20 +24,19 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
import org.springframework.util.NumberUtils;
|
||||
|
||||
/**
|
||||
* Implements greater-than operator.
|
||||
* Implements the greater-than operator.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @author Giovanni Dall'Oglio Risso
|
||||
* @since 3.0
|
||||
*/
|
||||
public class OpGT extends Operator {
|
||||
|
||||
|
||||
public OpGT(int pos, SpelNodeImpl... operands) {
|
||||
super(">", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
@@ -67,6 +66,12 @@ public class OpGT extends Operator {
|
||||
|
||||
return BooleanTypedValue.forValue(leftNumber.intValue() > rightNumber.intValue());
|
||||
}
|
||||
|
||||
if (left instanceof CharSequence && right instanceof CharSequence) {
|
||||
left = left.toString();
|
||||
right = right.toString();
|
||||
}
|
||||
|
||||
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) > 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,20 +27,18 @@ import org.springframework.util.NumberUtils;
|
||||
* Implements the less-than operator.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @author Giovanni Dall'Oglio Risso
|
||||
* @since 3.0
|
||||
*/
|
||||
public class OpLT extends Operator {
|
||||
|
||||
|
||||
public OpLT(int pos, SpelNodeImpl... operands) {
|
||||
super("<", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state)
|
||||
throws EvaluationException {
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
|
||||
@@ -68,6 +66,12 @@ public class OpLT extends Operator {
|
||||
|
||||
return BooleanTypedValue.forValue(leftNumber.intValue() < rightNumber.intValue());
|
||||
}
|
||||
|
||||
if (left instanceof CharSequence && right instanceof CharSequence) {
|
||||
left = left.toString();
|
||||
right = right.toString();
|
||||
}
|
||||
|
||||
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) < 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,12 +28,10 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
*/
|
||||
public class OpNE extends Operator {
|
||||
|
||||
|
||||
public OpNE(int pos, SpelNodeImpl... operands) {
|
||||
super("!=", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
|
||||
+21
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,15 +19,17 @@ package org.springframework.expression.spel.ast;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.NumberUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Common supertype for operators that operate on either one or two operands. In the case
|
||||
* of multiply or divide there would be two operands, but for unary plus or minus, there
|
||||
* is only one.
|
||||
* Common supertype for operators that operate on either one or two operands.
|
||||
* In the case of multiply or divide there would be two operands, but for
|
||||
* unary plus or minus, there is only one.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @author Giovanni Dall'Oglio Risso
|
||||
* @since 3.0
|
||||
*/
|
||||
@@ -70,6 +72,7 @@ public abstract class Operator extends SpelNodeImpl {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
protected boolean equalityCheck(ExpressionState state, Object left, Object right) {
|
||||
if (left instanceof Number && right instanceof Number) {
|
||||
Number leftNumber = (Number) left;
|
||||
@@ -96,11 +99,22 @@ public abstract class Operator extends SpelNodeImpl {
|
||||
return (leftNumber.intValue() == rightNumber.intValue());
|
||||
}
|
||||
|
||||
if (left != null && (left instanceof Comparable)) {
|
||||
return (state.getTypeComparator().compare(left, right) == 0);
|
||||
if (left instanceof CharSequence && right instanceof CharSequence) {
|
||||
return left.toString().equals(right.toString());
|
||||
}
|
||||
|
||||
return ObjectUtils.nullSafeEquals(left, right);
|
||||
if (ObjectUtils.nullSafeEquals(left, right)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (left instanceof Comparable && right instanceof Comparable) {
|
||||
Class<?> ancestor = ClassUtils.determineCommonAncestor(left.getClass(), right.getClass());
|
||||
if (ancestor != null && Comparable.class.isAssignableFrom(ancestor)) {
|
||||
return (state.getTypeComparator().compare(left, right) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -98,7 +98,7 @@ public class StandardTypeLocator implements TypeLocator {
|
||||
public Class<?> findType(String typeName) throws EvaluationException {
|
||||
String nameToLookup = typeName;
|
||||
try {
|
||||
return this.classLoader.loadClass(nameToLookup);
|
||||
return ClassUtils.forName(nameToLookup, this.classLoader);
|
||||
}
|
||||
catch (ClassNotFoundException ey) {
|
||||
// try any registered prefixes before giving up
|
||||
@@ -106,7 +106,7 @@ public class StandardTypeLocator implements TypeLocator {
|
||||
for (String prefix : this.knownPackagePrefixes) {
|
||||
try {
|
||||
nameToLookup = prefix + "." + typeName;
|
||||
return this.classLoader.loadClass(nameToLookup);
|
||||
return ClassUtils.forName(nameToLookup, this.classLoader);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// might be a different prefix
|
||||
|
||||
+213
-153
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,121 +16,24 @@
|
||||
|
||||
package org.springframework.expression.spel;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.expression.spel.ast.Operator;
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests the evaluation of expressions using relational operators.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @author Giovanni Dall'Oglio Risso
|
||||
*/
|
||||
public class OperatorTests extends AbstractExpressionTests {
|
||||
|
||||
@Test
|
||||
public void testIntegerLiteral() {
|
||||
evaluate("3", 3, Integer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRealLiteral() {
|
||||
evaluate("3.5", 3.5d, Double.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLessThan() {
|
||||
|
||||
evaluate("5 < 5", false, Boolean.class);
|
||||
evaluate("3 < 5", true, Boolean.class);
|
||||
evaluate("5 < 3", false, Boolean.class);
|
||||
evaluate("3L < 5L", true, Boolean.class);
|
||||
evaluate("5L < 3L", false, Boolean.class);
|
||||
evaluate("3.0d < 5.0d", true, Boolean.class);
|
||||
evaluate("5.0d < 3.0d", false, Boolean.class);
|
||||
evaluate("'abc' < 'def'",true,Boolean.class);
|
||||
evaluate("'def' < 'abc'",false,Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') < new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') < new java.math.BigDecimal('3')", false, Boolean.class);
|
||||
evaluate("3 < new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') < 5", true, Boolean.class);
|
||||
evaluate("3L < new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3.0d < new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3L < new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d < new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d < new java.math.BigDecimal('3.0')", false, Boolean.class);
|
||||
|
||||
evaluate("3 lt 5", true, Boolean.class);
|
||||
evaluate("5 lt 3", false, Boolean.class);
|
||||
evaluate("3L lt 5L", true, Boolean.class);
|
||||
evaluate("5L lt 3L", false, Boolean.class);
|
||||
evaluate("3.0d lT 5.0d", true, Boolean.class);
|
||||
evaluate("5.0d Lt 3.0d", false, Boolean.class);
|
||||
evaluate("'abc' LT 'def'",true,Boolean.class);
|
||||
evaluate("'def' lt 'abc'",false,Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') lt new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') lt new java.math.BigDecimal('3')", false, Boolean.class);
|
||||
evaluate("3 lt new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') lt 5", true, Boolean.class);
|
||||
evaluate("3L lt new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3.0d lt new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3L lt new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d lt new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d lt new java.math.BigDecimal('3.0')", false, Boolean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLessThanOrEqual() {
|
||||
evaluate("3 <= 5", true, Boolean.class);
|
||||
evaluate("5 <= 3", false, Boolean.class);
|
||||
evaluate("6 <= 6", true, Boolean.class);
|
||||
evaluate("3L <= 5L", true, Boolean.class);
|
||||
evaluate("5L <= 3L", false, Boolean.class);
|
||||
evaluate("5L <= 5L", true, Boolean.class);
|
||||
evaluate("3.0d <= 5.0d", true, Boolean.class);
|
||||
evaluate("5.0d <= 3.0d", false, Boolean.class);
|
||||
evaluate("5.0d <= 5.0d", true, Boolean.class);
|
||||
evaluate("'abc' <= 'def'",true,Boolean.class);
|
||||
evaluate("'def' <= 'abc'",false,Boolean.class);
|
||||
evaluate("'abc' <= 'abc'",true,Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') <= new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') <= new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') <= new java.math.BigDecimal('3')", false, Boolean.class);
|
||||
evaluate("3 <= new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') <= 5", true, Boolean.class);
|
||||
evaluate("3L <= new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3.0d <= new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3L <= new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d <= new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d <= new java.math.BigDecimal('3.0')", true, Boolean.class);
|
||||
|
||||
evaluate("3 le 5", true, Boolean.class);
|
||||
evaluate("5 le 3", false, Boolean.class);
|
||||
evaluate("6 Le 6", true, Boolean.class);
|
||||
evaluate("3L lE 5L", true, Boolean.class);
|
||||
evaluate("5L LE 3L", false, Boolean.class);
|
||||
evaluate("5L le 5L", true, Boolean.class);
|
||||
evaluate("3.0d LE 5.0d", true, Boolean.class);
|
||||
evaluate("5.0d lE 3.0d", false, Boolean.class);
|
||||
evaluate("5.0d Le 5.0d", true, Boolean.class);
|
||||
evaluate("'abc' Le 'def'",true,Boolean.class);
|
||||
evaluate("'def' LE 'abc'",false,Boolean.class);
|
||||
evaluate("'abc' le 'abc'",true,Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') le new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') le new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') le new java.math.BigDecimal('3')", false, Boolean.class);
|
||||
evaluate("3 le new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') le 5", true, Boolean.class);
|
||||
evaluate("3L le new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3.0d le new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3L le new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d le new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d le new java.math.BigDecimal('3.0')", true, Boolean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqual() {
|
||||
evaluate("3 == 5", false, Boolean.class);
|
||||
@@ -138,7 +41,6 @@ public class OperatorTests extends AbstractExpressionTests {
|
||||
evaluate("6 == 6", true, Boolean.class);
|
||||
evaluate("3.0f == 5.0f", false, Boolean.class);
|
||||
evaluate("3.0f == 3.0f", true, Boolean.class);
|
||||
evaluate("'abc' == null", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') == new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') == new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') == new java.math.BigDecimal('3')", false, Boolean.class);
|
||||
@@ -149,13 +51,19 @@ public class OperatorTests extends AbstractExpressionTests {
|
||||
evaluate("3L == new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d == new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d == new java.math.BigDecimal('3.0')", true, Boolean.class);
|
||||
evaluate("3.0f == 3.0d", true, Boolean.class);
|
||||
evaluate("10 == '10'", false, Boolean.class);
|
||||
evaluate("'abc' == 'abc'", true, Boolean.class);
|
||||
evaluate("'abc' == new java.lang.StringBuilder('abc')", true, Boolean.class);
|
||||
evaluate("'abc' == 'def'", false, Boolean.class);
|
||||
evaluate("'abc' == null", false, Boolean.class);
|
||||
evaluate("new org.springframework.expression.spel.OperatorTests$SubComparable() == new org.springframework.expression.spel.OperatorTests$OtherSubComparable()", true, Boolean.class);
|
||||
|
||||
evaluate("3 eq 5", false, Boolean.class);
|
||||
evaluate("5 eQ 3", false, Boolean.class);
|
||||
evaluate("6 Eq 6", true, Boolean.class);
|
||||
evaluate("3.0f eq 5.0f", false, Boolean.class);
|
||||
evaluate("3.0f EQ 3.0f", true, Boolean.class);
|
||||
evaluate("'abc' EQ null", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') eq new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') eq new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') eq new java.math.BigDecimal('3')", false, Boolean.class);
|
||||
@@ -166,6 +74,13 @@ public class OperatorTests extends AbstractExpressionTests {
|
||||
evaluate("3L eq new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d eq new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d eq new java.math.BigDecimal('3.0')", true, Boolean.class);
|
||||
evaluate("3.0f eq 3.0d", true, Boolean.class);
|
||||
evaluate("10 eq '10'", false, Boolean.class);
|
||||
evaluate("'abc' eq 'abc'", true, Boolean.class);
|
||||
evaluate("'abc' eq new java.lang.StringBuilder('abc')", true, Boolean.class);
|
||||
evaluate("'abc' eq 'def'", false, Boolean.class);
|
||||
evaluate("'abc' eq null", false, Boolean.class);
|
||||
evaluate("new org.springframework.expression.spel.OperatorTests$SubComparable() eq new org.springframework.expression.spel.OperatorTests$OtherSubComparable()", true, Boolean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -185,6 +100,13 @@ public class OperatorTests extends AbstractExpressionTests {
|
||||
evaluate("3L != new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d != new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d != new java.math.BigDecimal('3.0')", false, Boolean.class);
|
||||
evaluate("3.0f != 3.0d", false, Boolean.class);
|
||||
evaluate("10 != '10'", true, Boolean.class);
|
||||
evaluate("'abc' != 'abc'", false, Boolean.class);
|
||||
evaluate("'abc' != new java.lang.StringBuilder('abc')", false, Boolean.class);
|
||||
evaluate("'abc' != 'def'", true, Boolean.class);
|
||||
evaluate("'abc' != null", true, Boolean.class);
|
||||
evaluate("new org.springframework.expression.spel.OperatorTests$SubComparable() != new org.springframework.expression.spel.OperatorTests$OtherSubComparable()", false, Boolean.class);
|
||||
|
||||
evaluate("3 ne 5", true, Boolean.class);
|
||||
evaluate("5 nE 3", true, Boolean.class);
|
||||
@@ -201,6 +123,145 @@ public class OperatorTests extends AbstractExpressionTests {
|
||||
evaluate("3L ne new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d ne new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d ne new java.math.BigDecimal('3.0')", false, Boolean.class);
|
||||
evaluate("3.0f ne 3.0d", false, Boolean.class);
|
||||
evaluate("10 ne '10'", true, Boolean.class);
|
||||
evaluate("'abc' ne 'abc'", false, Boolean.class);
|
||||
evaluate("'abc' ne new java.lang.StringBuilder('abc')", false, Boolean.class);
|
||||
evaluate("'abc' ne 'def'", true, Boolean.class);
|
||||
evaluate("'abc' ne null", true, Boolean.class);
|
||||
evaluate("new org.springframework.expression.spel.OperatorTests$SubComparable() ne new org.springframework.expression.spel.OperatorTests$OtherSubComparable()", false, Boolean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLessThan() {
|
||||
evaluate("5 < 5", false, Boolean.class);
|
||||
evaluate("3 < 5", true, Boolean.class);
|
||||
evaluate("5 < 3", false, Boolean.class);
|
||||
evaluate("3L < 5L", true, Boolean.class);
|
||||
evaluate("5L < 3L", false, Boolean.class);
|
||||
evaluate("3.0d < 5.0d", true, Boolean.class);
|
||||
evaluate("5.0d < 3.0d", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') < new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') < new java.math.BigDecimal('3')", false, Boolean.class);
|
||||
evaluate("3 < new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') < 5", true, Boolean.class);
|
||||
evaluate("3L < new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3.0d < new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3L < new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d < new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d < new java.math.BigDecimal('3.0')", false, Boolean.class);
|
||||
evaluate("'abc' < 'def'", true, Boolean.class);
|
||||
evaluate("'abc' < new java.lang.StringBuilder('def')", true, Boolean.class);
|
||||
evaluate("'def' < 'abc'", false, Boolean.class);
|
||||
|
||||
evaluate("3 lt 5", true, Boolean.class);
|
||||
evaluate("5 lt 3", false, Boolean.class);
|
||||
evaluate("3L lt 5L", true, Boolean.class);
|
||||
evaluate("5L lt 3L", false, Boolean.class);
|
||||
evaluate("3.0d lT 5.0d", true, Boolean.class);
|
||||
evaluate("5.0d Lt 3.0d", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') lt new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') lt new java.math.BigDecimal('3')", false, Boolean.class);
|
||||
evaluate("3 lt new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') lt 5", true, Boolean.class);
|
||||
evaluate("3L lt new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3.0d lt new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3L lt new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d lt new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d lt new java.math.BigDecimal('3.0')", false, Boolean.class);
|
||||
evaluate("'abc' LT 'def'", true, Boolean.class);
|
||||
evaluate("'abc' lt new java.lang.StringBuilder('def')", true, Boolean.class);
|
||||
evaluate("'def' lt 'abc'", false, Boolean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLessThanOrEqual() {
|
||||
evaluate("3 <= 5", true, Boolean.class);
|
||||
evaluate("5 <= 3", false, Boolean.class);
|
||||
evaluate("6 <= 6", true, Boolean.class);
|
||||
evaluate("3L <= 5L", true, Boolean.class);
|
||||
evaluate("5L <= 3L", false, Boolean.class);
|
||||
evaluate("5L <= 5L", true, Boolean.class);
|
||||
evaluate("3.0d <= 5.0d", true, Boolean.class);
|
||||
evaluate("5.0d <= 3.0d", false, Boolean.class);
|
||||
evaluate("5.0d <= 5.0d", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') <= new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') <= new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') <= new java.math.BigDecimal('3')", false, Boolean.class);
|
||||
evaluate("3 <= new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') <= 5", true, Boolean.class);
|
||||
evaluate("3L <= new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3.0d <= new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3L <= new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d <= new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d <= new java.math.BigDecimal('3.0')", true, Boolean.class);
|
||||
evaluate("'abc' <= 'def'", true, Boolean.class);
|
||||
evaluate("'def' <= 'abc'", false, Boolean.class);
|
||||
evaluate("'abc' <= 'abc'", true, Boolean.class);
|
||||
|
||||
evaluate("3 le 5", true, Boolean.class);
|
||||
evaluate("5 le 3", false, Boolean.class);
|
||||
evaluate("6 Le 6", true, Boolean.class);
|
||||
evaluate("3L lE 5L", true, Boolean.class);
|
||||
evaluate("5L LE 3L", false, Boolean.class);
|
||||
evaluate("5L le 5L", true, Boolean.class);
|
||||
evaluate("3.0d LE 5.0d", true, Boolean.class);
|
||||
evaluate("5.0d lE 3.0d", false, Boolean.class);
|
||||
evaluate("5.0d Le 5.0d", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') le new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') le new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') le new java.math.BigDecimal('3')", false, Boolean.class);
|
||||
evaluate("3 le new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') le 5", true, Boolean.class);
|
||||
evaluate("3L le new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3.0d le new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("3L le new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d le new java.math.BigDecimal('3.1')", true, Boolean.class);
|
||||
evaluate("3.0d le new java.math.BigDecimal('3.0')", true, Boolean.class);
|
||||
evaluate("'abc' Le 'def'", true, Boolean.class);
|
||||
evaluate("'def' LE 'abc'", false, Boolean.class);
|
||||
evaluate("'abc' le 'abc'", true, Boolean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGreaterThan() {
|
||||
evaluate("3 > 5", false, Boolean.class);
|
||||
evaluate("5 > 3", true, Boolean.class);
|
||||
evaluate("3L > 5L", false, Boolean.class);
|
||||
evaluate("5L > 3L", true, Boolean.class);
|
||||
evaluate("3.0d > 5.0d", false, Boolean.class);
|
||||
evaluate("5.0d > 3.0d", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') > new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') > new java.math.BigDecimal('3')", true, Boolean.class);
|
||||
evaluate("3 > new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') > 5", false, Boolean.class);
|
||||
evaluate("3L > new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("3.0d > new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("3L > new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d > new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d > new java.math.BigDecimal('3.0')", false, Boolean.class);
|
||||
evaluate("'abc' > 'def'", false, Boolean.class);
|
||||
evaluate("'abc' > new java.lang.StringBuilder('def')", false, Boolean.class);
|
||||
evaluate("'def' > 'abc'", true, Boolean.class);
|
||||
|
||||
evaluate("3 gt 5", false, Boolean.class);
|
||||
evaluate("5 gt 3", true, Boolean.class);
|
||||
evaluate("3L gt 5L", false, Boolean.class);
|
||||
evaluate("5L gt 3L", true, Boolean.class);
|
||||
evaluate("3.0d gt 5.0d", false, Boolean.class);
|
||||
evaluate("5.0d gT 3.0d", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') gt new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') gt new java.math.BigDecimal('3')", true, Boolean.class);
|
||||
evaluate("3 gt new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') gt 5", false, Boolean.class);
|
||||
evaluate("3L gt new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("3.0d gt new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("3L gt new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d gt new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d gt new java.math.BigDecimal('3.0')", false, Boolean.class);
|
||||
evaluate("'abc' Gt 'def'", false, Boolean.class);
|
||||
evaluate("'abc' gt new java.lang.StringBuilder('def')", false, Boolean.class);
|
||||
evaluate("'def' GT 'abc'", true, Boolean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -213,10 +274,7 @@ public class OperatorTests extends AbstractExpressionTests {
|
||||
evaluate("5L >= 5L", true, Boolean.class);
|
||||
evaluate("3.0d >= 5.0d", false, Boolean.class);
|
||||
evaluate("5.0d >= 3.0d", true, Boolean.class);
|
||||
evaluate("5.0d <= 5.0d", true, Boolean.class);
|
||||
evaluate("'abc' >= 'def'",false,Boolean.class);
|
||||
evaluate("'def' >= 'abc'",true,Boolean.class);
|
||||
evaluate("'abc' >= 'abc'",true,Boolean.class);
|
||||
evaluate("5.0d >= 5.0d", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') >= new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') >= new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') >= new java.math.BigDecimal('3')", true, Boolean.class);
|
||||
@@ -227,11 +285,19 @@ public class OperatorTests extends AbstractExpressionTests {
|
||||
evaluate("3L >= new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d >= new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d >= new java.math.BigDecimal('3.0')", true, Boolean.class);
|
||||
evaluate("'abc' >= 'def'", false, Boolean.class);
|
||||
evaluate("'def' >= 'abc'", true, Boolean.class);
|
||||
evaluate("'abc' >= 'abc'", true, Boolean.class);
|
||||
|
||||
evaluate("3 GE 5", false, Boolean.class);
|
||||
evaluate("5 gE 3", true, Boolean.class);
|
||||
evaluate("6 Ge 6", true, Boolean.class);
|
||||
evaluate("3L ge 5L", false, Boolean.class);
|
||||
evaluate("5L ge 3L", true, Boolean.class);
|
||||
evaluate("5L ge 5L", true, Boolean.class);
|
||||
evaluate("3.0d ge 5.0d", false, Boolean.class);
|
||||
evaluate("5.0d ge 3.0d", true, Boolean.class);
|
||||
evaluate("5.0d ge 5.0d", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') ge new java.math.BigDecimal('5')", true, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') ge new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') ge new java.math.BigDecimal('3')", true, Boolean.class);
|
||||
@@ -242,41 +308,19 @@ public class OperatorTests extends AbstractExpressionTests {
|
||||
evaluate("3L ge new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d ge new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d ge new java.math.BigDecimal('3.0')", true, Boolean.class);
|
||||
evaluate("'abc' ge 'def'", false, Boolean.class);
|
||||
evaluate("'def' ge 'abc'", true, Boolean.class);
|
||||
evaluate("'abc' ge 'abc'", true, Boolean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGreaterThan() {
|
||||
evaluate("3 > 5", false, Boolean.class);
|
||||
evaluate("5 > 3", true, Boolean.class);
|
||||
evaluate("3L > 5L", false, Boolean.class);
|
||||
evaluate("5L > 3L", true, Boolean.class);
|
||||
evaluate("3.0d > 5.0d", false, Boolean.class);
|
||||
evaluate("5.0d > 3.0d", true, Boolean.class);
|
||||
evaluate("'abc' > 'def'",false,Boolean.class);
|
||||
evaluate("'def' > 'abc'",true,Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') > new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') > new java.math.BigDecimal('3')", true, Boolean.class);
|
||||
evaluate("3 > new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') > 5", false, Boolean.class);
|
||||
evaluate("3L > new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("3.0d > new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("3L > new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d > new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d > new java.math.BigDecimal('3.0')", false, Boolean.class);
|
||||
public void testIntegerLiteral() {
|
||||
evaluate("3", 3, Integer.class);
|
||||
}
|
||||
|
||||
evaluate("3.0d gt 5.0d", false, Boolean.class);
|
||||
evaluate("5.0d gT 3.0d", true, Boolean.class);
|
||||
evaluate("'abc' Gt 'def'",false,Boolean.class);
|
||||
evaluate("'def' GT 'abc'",true,Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') gt new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('5') gt new java.math.BigDecimal('3')", true, Boolean.class);
|
||||
evaluate("3 gt new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("new java.math.BigDecimal('3') gt 5", false, Boolean.class);
|
||||
evaluate("3L gt new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("3.0d gt new java.math.BigDecimal('5')", false, Boolean.class);
|
||||
evaluate("3L gt new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d gt new java.math.BigDecimal('3.1')", false, Boolean.class);
|
||||
evaluate("3.0d gt new java.math.BigDecimal('3.0')", false, Boolean.class);
|
||||
@Test
|
||||
public void testRealLiteral() {
|
||||
evaluate("3.5", 3.5d, Double.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -527,10 +571,10 @@ public class OperatorTests extends AbstractExpressionTests {
|
||||
|
||||
@Test
|
||||
public void testStrings() {
|
||||
evaluate("'abc' == 'abc'",true,Boolean.class);
|
||||
evaluate("'abc' == 'def'",false,Boolean.class);
|
||||
evaluate("'abc' != 'abc'",false,Boolean.class);
|
||||
evaluate("'abc' != 'def'",true,Boolean.class);
|
||||
evaluate("'abc' == 'abc'", true, Boolean.class);
|
||||
evaluate("'abc' == 'def'", false, Boolean.class);
|
||||
evaluate("'abc' != 'abc'", false, Boolean.class);
|
||||
evaluate("'abc' != 'def'", true, Boolean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -544,25 +588,41 @@ public class OperatorTests extends AbstractExpressionTests {
|
||||
evaluate("3L - 50L", -47L, Long.class);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
private Operator getOperatorNode(SpelExpression e) {
|
||||
SpelNode node = e.getAST();
|
||||
return (Operator)findNode(node,Operator.class);
|
||||
private Operator getOperatorNode(SpelExpression expr) {
|
||||
SpelNode node = expr.getAST();
|
||||
return findOperator(node);
|
||||
}
|
||||
|
||||
private SpelNode findNode(SpelNode node, Class<Operator> clazz) {
|
||||
if (clazz.isAssignableFrom(node.getClass())) {
|
||||
return node;
|
||||
private Operator findOperator(SpelNode node) {
|
||||
if (node instanceof Operator) {
|
||||
return (Operator) node;
|
||||
}
|
||||
int childCount = node.getChildCount();
|
||||
for (int i=0;i<childCount;i++) {
|
||||
SpelNode possible = findNode(node.getChild(i),clazz);
|
||||
if (possible!=null) {
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
Operator possible = findOperator(node.getChild(i));
|
||||
if (possible != null) {
|
||||
return possible;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static class BaseComparable implements Comparable<BaseComparable> {
|
||||
|
||||
@Override
|
||||
public int compareTo(BaseComparable other) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class SubComparable extends BaseComparable {
|
||||
}
|
||||
|
||||
|
||||
public static class OtherSubComparable extends BaseComparable {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,7 +18,6 @@ package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.rowset.CachedRowSet;
|
||||
import javax.sql.rowset.RowSetFactory;
|
||||
import javax.sql.rowset.RowSetProvider;
|
||||
@@ -26,6 +25,7 @@ import javax.sql.rowset.RowSetProvider;
|
||||
import org.springframework.core.JdkVersion;
|
||||
import org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSet;
|
||||
import org.springframework.jdbc.support.rowset.SqlRowSet;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link ResultSetExtractor} implementation that returns a Spring {@link SqlRowSet}
|
||||
@@ -134,12 +134,14 @@ public class SqlRowSetResultSetExtractor implements ResultSetExtractor<SqlRowSet
|
||||
*/
|
||||
private static class SunCachedRowSetFactory implements CachedRowSetFactory {
|
||||
|
||||
private static final Class<?> IMPLEMENTATION_CLASS;
|
||||
private static final Class<?> implementationClass;
|
||||
|
||||
static {
|
||||
try {
|
||||
IMPLEMENTATION_CLASS = Class.forName("com.sun.rowset.CachedRowSetImpl");
|
||||
implementationClass = ClassUtils.forName("com.sun.rowset.CachedRowSetImpl",
|
||||
SqlRowSetResultSetExtractor.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
@@ -147,12 +149,9 @@ public class SqlRowSetResultSetExtractor implements ResultSetExtractor<SqlRowSet
|
||||
@Override
|
||||
public CachedRowSet createCachedRowSet() throws SQLException {
|
||||
try {
|
||||
return (CachedRowSet) IMPLEMENTATION_CLASS.newInstance();
|
||||
return (CachedRowSet) implementationClass.newInstance();
|
||||
}
|
||||
catch (InstantiationException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,8 +20,9 @@ import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* The HSQL specific implementation of the {@link TableMetaDataProvider}.
|
||||
* Supports a feature for retreiving generated keys without the JDBC 3.0 getGeneratedKeys support.
|
||||
* The HSQL specific implementation of {@link TableMetaDataProvider}.
|
||||
* Supports a feature for retrieving generated keys without the JDBC 3.0
|
||||
* {@code getGeneratedKeys} support.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
|
||||
+11
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,8 +29,8 @@ import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Oracle-specific implementation of the {@link org.springframework.jdbc.core.metadata.TableMetaDataProvider}.
|
||||
* Supports a feature for including synonyms in the metadata lookup. Also supports lookup of current schema using
|
||||
* the sys_context.
|
||||
* Supports a feature for including synonyms in the metadata lookup. Also supports lookup of current schema
|
||||
* using the sys_context.
|
||||
*
|
||||
* <p>Thanks to Mike Youngstrom and Bruce Campbell for submitting the original suggestion for the Oracle
|
||||
* current schema lookup implementation.
|
||||
@@ -56,9 +56,10 @@ public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider {
|
||||
lookupDefaultSchema(databaseMetaData);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getDefaultSchema() {
|
||||
if (defaultSchema != null) {
|
||||
if (this.defaultSchema != null) {
|
||||
return defaultSchema;
|
||||
}
|
||||
return super.getDefaultSchema();
|
||||
@@ -81,7 +82,7 @@ public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider {
|
||||
}
|
||||
boolean isOracleCon;
|
||||
try {
|
||||
Class<?> oracleConClass = getClass().getClassLoader().loadClass("oracle.jdbc.OracleConnection");
|
||||
Class<?> oracleConClass = con.getClass().getClassLoader().loadClass("oracle.jdbc.OracleConnection");
|
||||
isOracleCon = oracleConClass.isInstance(con);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
@@ -107,7 +108,7 @@ public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider {
|
||||
ReflectionUtils.makeAccessible(getIncludeSynonyms);
|
||||
originalValueForIncludeSynonyms = (Boolean) getIncludeSynonyms.invoke(con);
|
||||
|
||||
setIncludeSynonyms = con.getClass().getMethod("setIncludeSynonyms", new Class<?>[] {boolean.class});
|
||||
setIncludeSynonyms = con.getClass().getMethod("setIncludeSynonyms", boolean.class);
|
||||
ReflectionUtils.makeAccessible(setIncludeSynonyms);
|
||||
setIncludeSynonyms.invoke(con, Boolean.TRUE);
|
||||
}
|
||||
@@ -126,9 +127,7 @@ public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider {
|
||||
}
|
||||
|
||||
/*
|
||||
* Oracle implementation for detecting current schema
|
||||
*
|
||||
* @param databaseMetaData
|
||||
* Oracle-based implementation for detecting the current schema.
|
||||
*/
|
||||
private void lookupDefaultSchema(DatabaseMetaData databaseMetaData) {
|
||||
try {
|
||||
@@ -144,7 +143,9 @@ public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider {
|
||||
cstmt.close();
|
||||
}
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,8 +20,9 @@ import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* The PostgreSQL specific implementation of the {@link org.springframework.jdbc.core.metadata.TableMetaDataProvider}.
|
||||
* Suports a feature for retreiving generated keys without the JDBC 3.0 getGeneratedKeys support.
|
||||
* The PostgreSQL specific implementation of {@link TableMetaDataProvider}.
|
||||
* Supports a feature for retrieving generated keys without the JDBC 3.0
|
||||
* {@code getGeneratedKeys} support.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
@@ -38,7 +39,10 @@ public class PostgresTableMetaDataProvider extends GenericTableMetaDataProvider
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
logger.warn("PostgreSQL does not support getGeneratedKeys or INSERT ... RETURNING in version " + getDatabaseVersion());
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("PostgreSQL does not support getGeneratedKeys or INSERT ... RETURNING in version " +
|
||||
getDatabaseVersion());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -47,4 +51,5 @@ public class PostgresTableMetaDataProvider extends GenericTableMetaDataProvider
|
||||
public String getSimpleQueryForGetGeneratedKey(String tableName, String keyColumnName) {
|
||||
return "RETURNING " + keyColumnName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,10 +33,9 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
* {@link org.springframework.transaction.PlatformTransactionManager}
|
||||
* implementation for a single JDBC {@link javax.sql.DataSource}. This class is
|
||||
* capable of working in any environment with any JDBC driver, as long as the setup
|
||||
* uses a JDBC 2.0 Standard Extensions / JDBC 3.0 {@code javax.sql.DataSource}
|
||||
* as its Connection factory mechanism. Binds a JDBC Connection from the specified
|
||||
* DataSource to the current thread, potentially allowing for one thread-bound
|
||||
* Connection per DataSource.
|
||||
* uses a {@code javax.sql.DataSource} as its {@code Connection} factory mechanism.
|
||||
* Binds a JDBC Connection from the specified DataSource to the current thread,
|
||||
* potentially allowing for one thread-bound Connection per DataSource.
|
||||
*
|
||||
* <p><b>Note: The DataSource that this transaction manager operates on needs
|
||||
* to return independent Connections.</b> The Connections may come from a pool
|
||||
@@ -75,8 +74,8 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
* an actual JDBC Connection from the target DataSource until a Statement gets executed,
|
||||
* lazily applying the specified transaction settings to the target Connection.
|
||||
*
|
||||
* <p>On JDBC 3.0, this transaction manager supports nested transactions via the
|
||||
* JDBC 3.0 {@link java.sql.Savepoint} mechanism. The
|
||||
* <p>This transaction manager supports nested transactions via the JDBC 3.0
|
||||
* {@link java.sql.Savepoint} mechanism. The
|
||||
* {@link #setNestedTransactionAllowed "nestedTransactionAllowed"} flag defaults
|
||||
* to "true", since nested transactions will work without restrictions on JDBC
|
||||
* drivers that support savepoints (such as the Oracle JDBC driver).
|
||||
|
||||
+7
-4
@@ -21,6 +21,7 @@ import javax.sql.DataSource;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.jdbc.datasource.init.ScriptUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -161,7 +162,9 @@ public class EmbeddedDatabaseBuilder {
|
||||
|
||||
/**
|
||||
* Specify the statement separator used in all SQL scripts, if a custom one.
|
||||
* <p>Default is ";".
|
||||
* <p>Defaults to {@code ";"} if not specified and falls back to {@code "\n"}
|
||||
* as a last resort; may be set to {@link ScriptUtils#EOF_STATEMENT_SEPARATOR}
|
||||
* to signal that each script contains a single statement without a separator.
|
||||
* @param separator the statement separator
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
* @since 4.0.3
|
||||
@@ -173,7 +176,7 @@ public class EmbeddedDatabaseBuilder {
|
||||
|
||||
/**
|
||||
* Specify the single-line comment prefix used in all SQL scripts.
|
||||
* <p>Default is "--".
|
||||
* <p>Defaults to {@code "--"}.
|
||||
* @param commentPrefix the prefix for single-line comments
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
* @since 4.0.3
|
||||
@@ -185,7 +188,7 @@ public class EmbeddedDatabaseBuilder {
|
||||
|
||||
/**
|
||||
* Specify the start delimiter for block comments in all SQL scripts.
|
||||
* <p>Default is "/*".
|
||||
* <p>Defaults to {@code "/*"}.
|
||||
* @param blockCommentStartDelimiter the start delimiter for block comments
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
* @since 4.0.3
|
||||
@@ -199,7 +202,7 @@ public class EmbeddedDatabaseBuilder {
|
||||
|
||||
/**
|
||||
* Specify the end delimiter for block comments in all SQL scripts.
|
||||
* <p>Default is "*/".
|
||||
* <p>Defaults to <code>"*/"</code>.
|
||||
* @param blockCommentEndDelimiter the end delimiter for block comments
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
* @since 4.0.3
|
||||
|
||||
+8
-6
@@ -136,16 +136,18 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
||||
|
||||
/**
|
||||
* Specify the statement separator, if a custom one.
|
||||
* <p>Default is ";".
|
||||
* @param separator the statement separator
|
||||
* <p>Defaults to {@code ";"} if not specified and falls back to {@code "\n"}
|
||||
* as a last resort; may be set to {@link ScriptUtils#EOF_STATEMENT_SEPARATOR}
|
||||
* to signal that each script contains a single statement without a separator.
|
||||
* @param separator the script statement separator
|
||||
*/
|
||||
public void setSeparator(String separator) {
|
||||
this.separator = separator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the prefix that identifies line comments within the SQL scripts.
|
||||
* <p>Default is "--".
|
||||
* Set the prefix that identifies single-line comments within the SQL scripts.
|
||||
* <p>Defaults to {@code "--"}.
|
||||
* @param commentPrefix the prefix for single-line comments
|
||||
*/
|
||||
public void setCommentPrefix(String commentPrefix) {
|
||||
@@ -155,7 +157,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
||||
/**
|
||||
* Set the start delimiter that identifies block comments within the SQL
|
||||
* scripts.
|
||||
* <p>Default is "/*".
|
||||
* <p>Defaults to {@code "/*"}.
|
||||
* @param blockCommentStartDelimiter the start delimiter for block comments
|
||||
* @since 4.0.3
|
||||
* @see #setBlockCommentEndDelimiter
|
||||
@@ -167,7 +169,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
||||
/**
|
||||
* Set the end delimiter that identifies block comments within the SQL
|
||||
* scripts.
|
||||
* <p>Default is "*/".
|
||||
* <p>Defaults to <code>"*/"</code>.
|
||||
* @param blockCommentEndDelimiter the end delimiter for block comments
|
||||
* @since 4.0.3
|
||||
* @see #setBlockCommentStartDelimiter
|
||||
|
||||
+18
-2
@@ -61,6 +61,17 @@ public abstract class ScriptUtils {
|
||||
*/
|
||||
public static final String FALLBACK_STATEMENT_SEPARATOR = "\n";
|
||||
|
||||
/**
|
||||
* End of file (EOF) SQL statement separator.
|
||||
* <p>This value may be supplied as the {@code separator} to {@link
|
||||
* #executeSqlScript(Connection, EncodedResource, boolean, boolean, String, String, String, String)}
|
||||
* to denote that an SQL script contains a single statement (potentially
|
||||
* spanning multiple lines) with no explicit statement separator. Note that
|
||||
* such a script should not actually contain this value; it is merely a
|
||||
* <em>virtual</em> statement separator.
|
||||
*/
|
||||
public static final String EOF_STATEMENT_SEPARATOR = "^^^ END OF SCRIPT ^^^";
|
||||
|
||||
/**
|
||||
* Default prefix for line comments within SQL scripts.
|
||||
*/
|
||||
@@ -399,12 +410,17 @@ public abstract class ScriptUtils {
|
||||
* typically "--"
|
||||
* @param separator the script statement separator; defaults to
|
||||
* {@value #DEFAULT_STATEMENT_SEPARATOR} if not specified and falls back to
|
||||
* {@value #FALLBACK_STATEMENT_SEPARATOR} as a last resort
|
||||
* {@value #FALLBACK_STATEMENT_SEPARATOR} as a last resort; may be set to
|
||||
* {@value #EOF_STATEMENT_SEPARATOR} to signal that the script contains a
|
||||
* single statement without a separator
|
||||
* @param blockCommentStartDelimiter the <em>start</em> block comment delimiter; never
|
||||
* {@code null} or empty
|
||||
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter; never
|
||||
* {@code null} or empty
|
||||
* @throws ScriptException if an error occurred while executing the SQL script
|
||||
* @see #DEFAULT_STATEMENT_SEPARATOR
|
||||
* @see #FALLBACK_STATEMENT_SEPARATOR
|
||||
* @see #EOF_STATEMENT_SEPARATOR
|
||||
*/
|
||||
public static void executeSqlScript(Connection connection, EncodedResource resource, boolean continueOnError,
|
||||
boolean ignoreFailedDrops, String commentPrefix, String separator, String blockCommentStartDelimiter,
|
||||
@@ -428,7 +444,7 @@ public abstract class ScriptUtils {
|
||||
if (separator == null) {
|
||||
separator = DEFAULT_STATEMENT_SEPARATOR;
|
||||
}
|
||||
if (!containsSqlScriptDelimiters(script, separator)) {
|
||||
if (!EOF_STATEMENT_SEPARATOR.equals(separator) && !containsSqlScriptDelimiters(script, separator)) {
|
||||
separator = FALLBACK_STATEMENT_SEPARATOR;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,8 @@
|
||||
|
||||
package org.springframework.jdbc.object;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
@@ -33,9 +33,7 @@ import org.springframework.jdbc.core.SqlParameter;
|
||||
* {@link #execute} method.
|
||||
*
|
||||
* <p>The inherited {@code sql} property is the name of the stored
|
||||
* procedure in the RDBMS. Note that JDBC 3.0 introduces named parameters,
|
||||
* although the other features provided by this class are still necessary
|
||||
* in JDBC 3.0.
|
||||
* procedure in the RDBMS.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Thomas Risberg
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,7 +20,6 @@ import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
@@ -51,7 +50,7 @@ import org.springframework.jdbc.support.JdbcUtils;
|
||||
* is rolled back, the unused values will never be served. The maximum hole size in
|
||||
* numbering is consequently the value of cacheSize.
|
||||
*
|
||||
* <b>HINT:</b> Since Derby supports the JDBC 3.0 {@code getGeneratedKeys} method,
|
||||
* <b>HINT:</b> Since Derby supports the JDBC 3.0 {@code getGeneratedKeys} method,
|
||||
* it is recommended to use IDENTITY columns directly in the tables and then utilizing
|
||||
* a {@link org.springframework.jdbc.support.KeyHolder} when calling the with the
|
||||
* {@code update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder)}
|
||||
|
||||
+24
-8
@@ -1,16 +1,32 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.support.incrementer;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Statement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* {@link DataFieldMaxValueIncrementer} that increments the maximum value of a given SQL Server table
|
||||
* with the equivalent of an auto-increment column. Note: If you use this class, your Derby key
|
||||
@@ -32,8 +48,8 @@ import java.sql.SQLException;
|
||||
* is rolled back, the unused values will never be served. The maximum hole size in
|
||||
* numbering is consequently the value of cacheSize.
|
||||
*
|
||||
* <b>HINT:</b> Since Microsoft SQL Server supports the JDBC 3.0 {@code getGeneratedKeys} method,
|
||||
* it is recommended to use IDENTITY columns directly in the tables and then using a
|
||||
* <b>HINT:</b> Since Microsoft SQL Server supports the JDBC 3.0 {@code getGeneratedKeys}
|
||||
* method, it is recommended to use IDENTITY columns directly in the tables and then using a
|
||||
* {@link org.springframework.jdbc.core.simple.SimpleJdbcInsert} or utilizing
|
||||
* a {@link org.springframework.jdbc.support.KeyHolder} when calling the with the
|
||||
* {@code update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder)}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,7 +40,7 @@ import javax.sql.DataSource;
|
||||
* is rolled back, the unused values will never be served. The maximum hole size in
|
||||
* numbering is consequently the value of cacheSize.
|
||||
*
|
||||
* <b>HINT:</b> Since Sybase Anywhere supports the JDBC 3.0 {@code getGeneratedKeys} method,
|
||||
* <b>HINT:</b> Since Sybase Anywhere supports the JDBC 3.0 {@code getGeneratedKeys} method,
|
||||
* it is recommended to use IDENTITY columns directly in the tables and then using a
|
||||
* {@link org.springframework.jdbc.core.simple.SimpleJdbcInsert} or utilizing
|
||||
* a {@link org.springframework.jdbc.support.KeyHolder} when calling the with the
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user