Compare commits

..

1 Commits

Author SHA1 Message Date
Spring Buildmaster d3fa0733d5 Release version 4.3.5.RELEASE 2016-12-21 11:11:41 +00:00
1580 changed files with 24024 additions and 37256 deletions
+90 -95
View File
@@ -34,50 +34,50 @@ configure(allprojects) { project ->
ext.aspectjVersion = "1.8.9"
ext.caffeineVersion = "2.3.5"
ext.eclipselinkVersion = "2.4.2"
ext.ehcacheVersion = "2.10.4"
ext.ehcacheVersion = "2.10.3"
ext.ehcachejcacheVersion = "1.0.1"
ext.ehcache3Version = "3.1.4"
ext.ehcache3Version = "3.1.3"
ext.ejbVersion = "3.0"
ext.fileuploadVersion = "1.3.3"
ext.fileuploadVersion = "1.3.2"
ext.freemarkerVersion = "2.3.23"
ext.groovyVersion = "2.4.15"
ext.gsonVersion = "2.8.2"
ext.groovyVersion = "2.4.7"
ext.gsonVersion = "2.8.0"
ext.guavaVersion = "20.0"
ext.hamcrestVersion = "1.3"
ext.hibernate3Version = "3.6.10.Final"
ext.hibernate4Version = "4.3.11.Final"
ext.hibernate5Version = "5.2.10.Final"
ext.hibernate5Version = "5.2.6.Final"
ext.hibval4Version = "4.3.2.Final"
ext.hibval5Version = "5.2.5.Final"
ext.hibval5Version = "5.2.4.Final"
ext.hsqldbVersion = "2.3.4"
ext.httpasyncVersion = "4.1.3"
ext.httpclientVersion = "4.5.5"
ext.jackson2Version = "2.8.11.2"
ext.httpasyncVersion = "4.1.2"
ext.httpclientVersion = "4.5.2"
ext.jackson2Version = "2.8.5"
ext.jasperreportsVersion = "6.2.1" // our tests fail with JR-internal NPEs against 6.2.2 and higher
ext.javamailVersion = "1.5.6"
ext.jettyVersion = "9.3.14.v20161028" // as of 9.3.15, Jetty has hard Servlet 3.1 requirement
ext.jetty94Version = "9.4.6.v20170531" // for spring-websocket support, optimized for Jetty 9.4
ext.jodaVersion = "2.9.9"
ext.jrubyVersion = "1.7.27" // JRuby 9000 primarily supported through JSR-223 (StandardScriptFactory)
ext.jettyVersion = "9.3.14.v20161028"
ext.jetty94Version = "9.4.0.v20161208" // for spring-websocket support
ext.jodaVersion = "2.9.6"
ext.jrubyVersion = "1.7.26" // JRuby 9000 only supported through JSR-223 (StandardScriptFactory)
ext.jtaVersion = "1.2"
ext.junitVersion = "4.12"
ext.log4jVersion = "1.2.17"
ext.nettyVersion = "4.1.29.Final"
ext.nettyVersion = "4.1.6.Final"
ext.okhttpVersion = "2.7.5"
ext.okhttp3Version = "3.8.1"
ext.openjpaVersion = "2.4.2"
ext.okhttp3Version = "3.5.0"
ext.openjpaVersion = "2.4.1"
ext.poiVersion = "3.14"
ext.reactorVersion = "2.0.8.RELEASE"
ext.romeVersion = "1.7.4"
ext.slf4jVersion = "1.7.25"
ext.romeVersion = "1.7.0"
ext.slf4jVersion = "1.7.21"
ext.snakeyamlVersion = "1.17"
ext.snifferVersion = "1.16"
ext.snifferVersion = "1.15"
ext.testngVersion = "6.9.10"
ext.tiles2Version = "2.2.2"
ext.tiles3Version = "3.0.7"
ext.tomcatVersion = "8.5.33"
ext.tomcatVersion = "8.5.9"
ext.tyrusVersion = "1.3.5" // constrained by WebLogic 12.1.3 support
ext.undertowVersion = "1.3.33.Final"
ext.undertowVersion = "1.3.25.Final"
ext.xmlunitVersion = "1.6"
ext.xstreamVersion = "1.4.9"
@@ -217,6 +217,7 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
configurations {
jacoco
}
dependencies {
jacoco("org.jacoco:org.jacoco.agent:0.7.5.201505241946:runtime")
}
@@ -250,16 +251,16 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
options.links(project.ext.javadocLinks)
options.addStringOption('Xdoclint:none', '-quiet')
// Suppress warnings due to cross-module @see and @link references.
// Note that global 'api' task does display all warnings.
// suppress warnings due to cross-module @see and @link references;
// note that global 'api' task does display all warnings.
logging.captureStandardError LogLevel.INFO
logging.captureStandardOutput LogLevel.INFO // suppress "## warnings" message
logging.captureStandardOutput LogLevel.INFO // suppress "## warnings" message
}
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
// Don't include or exclude anything explicitly by default. See SPR-12085.
// don't include or exclude anything explicitly by default. See SPR-12085.
}
task javadocJar(type: Jar) {
@@ -275,7 +276,6 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
project("spring-build-src") {
description = "Exposes gradle buildSrc for IDE support"
apply plugin: "groovy"
dependencies {
@@ -293,8 +293,8 @@ project("spring-core") {
// both into the spring-core jar. cglib 3.2 itself depends on asm 5.x and is therefore
// further transformed by the JarJar task to depend on org.springframework.asm; this
// avoids including two different copies of asm unnecessarily.
def cglibVersion = "3.2.6"
def objenesisVersion = "2.6"
def cglibVersion = "3.2.4"
def objenesisVersion = "2.4"
configurations {
jarjar
@@ -314,9 +314,9 @@ project("spring-core") {
configurations.cglib.each { originalJar ->
zipfileset(src: originalJar)
}
// Repackage net.sf.cglib => org.springframework.cglib
// repackage net.sf.cglib => org.springframework.cglib
rule(pattern: "net.sf.cglib.**", result: "org.springframework.cglib.@1")
// As mentioned above, transform cglib's internal asm dependencies from
// as mentioned above, transform cglib"s internal asm dependencies from
// org.objectweb.asm => org.springframework.asm. Doing this counts on the
// the fact that Spring and cglib depend on the same version of asm!
rule(pattern: "org.objectweb.asm.**", result: "org.springframework.asm.@1")
@@ -337,7 +337,7 @@ project("spring-core") {
configurations.objenesis.each { originalJar ->
zipfileset(src: originalJar)
}
// Repackage org.objenesis => org.springframework.objenesis
// repackage org.objenesis => org.springframework.objenesis
rule(pattern: "org.objenesis.**", result: "org.springframework.objenesis.@1")
}
}
@@ -364,7 +364,7 @@ project("spring-core") {
}
jar {
// Inline repackaged cglib classes directly into spring-core jar
// inline repackaged cglib classes directly into the spring-core jar
dependsOn cglibRepackJar
from(zipTree(cglibRepackJar.archivePath)) {
include "org/springframework/cglib/**"
@@ -393,7 +393,6 @@ project("spring-beans") {
project("spring-beans-groovy") {
description "Groovy Bean Definitions"
merge.into = project(":spring-beans")
apply plugin: "groovy"
@@ -402,8 +401,8 @@ project("spring-beans-groovy") {
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
}
// This module's Java and Groovy sources need to be compiled together.
compileJava.enabled = false
// this module's Java and Groovy sources need to be compiled together
compileJava.enabled=false
sourceSets {
main {
groovy {
@@ -469,14 +468,13 @@ project("spring-instrument-tomcat") {
project("spring-context") {
description = "Spring Context"
apply plugin: "groovy"
dependencies {
compile(project(":spring-aop"))
compile(project(":spring-beans"))
compile(project(":spring-core"))
compile(project(":spring-expression"))
compile(project(":spring-core"))
compile(files(project(":spring-core").cglibRepackJar))
optional(project(":spring-instrument"))
optional("javax.inject:javax.inject:1")
@@ -489,7 +487,7 @@ project("spring-context") {
optional("joda-time:joda-time:${jodaVersion}")
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
optional("org.beanshell:bsh:2.0b5")
optional("org.beanshell:bsh:2.0b4")
optional("org.jruby:jruby:${jrubyVersion}")
testCompile("javax.inject:javax.inject-tck:1")
testCompile("org.javamoney:moneta:1.1")
@@ -499,44 +497,13 @@ project("spring-context") {
}
}
project("spring-oxm") {
description = "Spring Object/XML Marshalling"
apply from: "oxm.gradle"
dependencies {
compile(project(":spring-beans"))
compile(project(":spring-core"))
optional("org.codehaus.castor:castor-xml:1.4.1") {
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'
}
optional("com.thoughtworks.xstream:xstream:${xstreamVersion}") {
exclude group: 'xpp3', module: 'xpp3_min'
exclude group: 'xmlpull', module: 'xmlpull'
}
optional("org.jibx:jibx-run:1.2.6")
testCompile(project(":spring-context"))
testCompile("org.ogce:xpp3:1.1.6")
testCompile("org.codehaus.jettison:jettison:1.3.8") {
exclude group: 'stax', module: 'stax-api'
}
testCompile("xmlunit:xmlunit:${xmlunitVersion}")
testCompile(files(genCastor.classesDir).builtBy(genCastor))
testCompile(files(genJaxb.classesDir).builtBy(genJaxb))
testCompile(files(genXmlbeans.classesDir).builtBy(genXmlbeans))
}
}
project("spring-messaging") {
description = "Spring Messaging"
dependencies {
compile(project(":spring-beans"))
compile(project(":spring-context"))
compile(project(":spring-core"))
compile(project(":spring-context"))
optional(project(":spring-oxm"))
optional("io.projectreactor:reactor-core:${reactorVersion}")
optional("io.projectreactor:reactor-net:${reactorVersion}") {
@@ -588,14 +555,45 @@ project("spring-tx") {
}
}
project("spring-oxm") {
description = "Spring Object/XML Marshalling"
apply from: "oxm.gradle"
dependencies {
compile(project(":spring-beans"))
compile(project(":spring-core"))
optional("org.codehaus.castor:castor-xml:1.4.1") {
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'
}
optional("com.thoughtworks.xstream:xstream:${xstreamVersion}") {
exclude group: 'xpp3', module: 'xpp3_min'
exclude group: 'xmlpull', module: 'xmlpull'
}
optional("org.jibx:jibx-run:1.2.6")
testCompile(project(":spring-context"))
testCompile("xmlunit:xmlunit:${xmlunitVersion}")
testCompile("xpp3:xpp3:1.1.4c")
testCompile("org.codehaus.jettison:jettison:1.3.8") {
exclude group: 'stax', module: 'stax-api'
}
testCompile(files(genCastor.classesDir).builtBy(genCastor))
testCompile(files(genJaxb.classesDir).builtBy(genJaxb))
testCompile(files(genXmlbeans.classesDir).builtBy(genXmlbeans))
}
}
project("spring-jms") {
description = "Spring JMS"
dependencies {
compile(project(":spring-aop"))
compile(project(":spring-beans"))
compile(project(":spring-context"))
compile(project(":spring-core"))
compile(project(":spring-beans"))
compile(project(":spring-aop"))
compile(project(":spring-context"))
compile(project(":spring-messaging"))
compile(project(":spring-tx"))
provided("javax.jms:jms-api:1.1-rev-1")
@@ -627,9 +625,9 @@ project("spring-context-support") {
description = "Spring Context Support"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-beans"))
compile(project(":spring-context"))
compile(project(":spring-core"))
optional(project(":spring-jdbc")) // for Quartz support
optional(project(":spring-tx")) // for Quartz support
optional("javax.mail:javax.mail-api:${javamailVersion}")
@@ -658,14 +656,11 @@ project("spring-context-support") {
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
testRuntime("com.sun.mail:javax.mail:${javamailVersion}")
testRuntime("org.ehcache:jcache:${ehcachejcacheVersion}")
testRuntime("org.ehcache:ehcache:${ehcache3Version}")
testRuntime("org.terracotta:management-model:2.3.0")
}
}
project("spring-web") {
description = "Spring Web"
apply plugin: "groovy"
// Re-generate Protobuf classes from *.proto files and move them in test sources
@@ -704,7 +699,7 @@ project("spring-web") {
optional("com.squareup.okhttp:okhttp:${okhttpVersion}")
optional("com.squareup.okhttp3:okhttp:${okhttp3Version}")
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.8.11")
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson2Version}")
optional("com.google.code.gson:gson:${gsonVersion}")
optional("com.rometools:rome:${romeVersion}")
optional("org.eclipse.jetty:jetty-servlet:${jettyVersion}") {
@@ -720,14 +715,13 @@ project("spring-web") {
testCompile(project(":spring-context-support")) // for JafMediaTypeFactory
testCompile("xmlunit:xmlunit:${xmlunitVersion}")
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
testCompile("org.skyscreamer:jsonassert:1.4.0")
testCompile("org.apache.taglibs:taglibs-standard-jstlel:1.2.1") {
exclude group: "org.apache.taglibs", module: "taglibs-standard-spec"
}
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-joda:2.8.11")
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.8.11")
testCompile("com.fasterxml.jackson.module:jackson-module-kotlin:2.8.11.1")
testCompile("com.squareup.okhttp3:mockwebserver:${okhttp3Version}")
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-joda:${jackson2Version}")
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:${jackson2Version}")
testCompile("com.fasterxml.jackson.module:jackson-module-kotlin:${jackson2Version}")
testCompile("com.squareup.okhttp3:mockwebserver:${okhttp3Version}")
testRuntime("com.sun.mail:javax.mail:${javamailVersion}")
}
}
@@ -837,7 +831,7 @@ project("spring-webmvc") {
exclude group: "org.springframework", module: "spring-context"
}
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.8.11")
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson2Version}")
optional("com.rometools:rome:${romeVersion}")
optional("javax.el:javax.el-api:2.2.5")
optional("org.apache.tiles:tiles-api:${tiles3Version}")
@@ -857,7 +851,7 @@ project("spring-webmvc") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
exclude group: "org.springframework", module: "spring-web"
}
optional('org.webjars:webjars-locator:0.32-1')
optional('org.webjars:webjars-locator:0.32')
testCompile("xmlunit:xmlunit:${xmlunitVersion}")
testCompile("dom4j:dom4j:1.6.1") {
exclude group: "xml-apis", module: "xml-apis"
@@ -877,10 +871,10 @@ project("spring-webmvc") {
testCompile("org.hibernate:hibernate-validator:${hibval4Version}")
testCompile("org.apache.httpcomponents:httpclient:${httpclientVersion}")
testCompile("commons-fileupload:commons-fileupload:${fileuploadVersion}")
testCompile("commons-io:commons-io:1.4")
testCompile("commons-io:commons-io:1.3")
testCompile("joda-time:joda-time:${jodaVersion}")
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
testCompile("org.mozilla:rhino:1.7.7.2")
testCompile("org.mozilla:rhino:1.7.7.1")
testRuntime("org.jruby:jruby:${jrubyVersion}")
testRuntime("org.python:jython-standalone:2.5.3")
testRuntime("org.webjars:underscorejs:1.8.3")
@@ -938,8 +932,8 @@ project("spring-websocket") {
description = "Spring WebSocket"
dependencies {
compile(project(":spring-context"))
compile(project(":spring-core"))
compile(project(":spring-context"))
compile(project(":spring-web"))
optional(project(":spring-messaging"))
optional(project(":spring-webmvc"))
@@ -984,12 +978,11 @@ project("spring-test") {
dependencies {
compile(project(":spring-core"))
optional(project(":spring-aop"))
optional(project(":spring-beans"))
optional(project(":spring-context"))
optional(project(":spring-jdbc"))
optional(project(":spring-orm"))
optional(project(":spring-tx"))
optional(project(":spring-orm"))
optional(project(":spring-web"))
optional(project(":spring-webmvc"))
optional(project(":spring-webmvc-portlet"))
@@ -1014,7 +1007,7 @@ project("spring-test") {
optional("org.seleniumhq.selenium:htmlunit-driver:2.23.2")
optional("org.seleniumhq.selenium:selenium-java:2.53.1")
optional("org.skyscreamer:jsonassert:1.4.0")
optional("com.jayway.jsonpath:json-path:2.3.0")
optional("com.jayway.jsonpath:json-path:2.2.0")
testCompile(project(":spring-context-support"))
testCompile(project(":spring-oxm"))
testCompile("javax.mail:javax.mail-api:${javamailVersion}")
@@ -1037,6 +1030,8 @@ project("spring-test") {
testCompile("org.apache.httpcomponents:httpclient:${httpclientVersion}")
testCompile("javax.cache:cache-api:1.0.0")
testRuntime("log4j:log4j:${log4jVersion}")
testRuntime("org.ehcache:ehcache:${ehcache3Version}")
testRuntime("org.terracotta:management-model:2.3.0")
}
task testNG(type: Test) {
@@ -1181,7 +1176,7 @@ configure(rootProject) {
// don't publish the default jar for the root project
configurations.archives.artifacts.clear()
dependencies { // for integration tests
dependencies { // for integration tests
testCompile(project(":spring-aop"))
testCompile(project(":spring-beans"))
testCompile(project(":spring-context"))
@@ -1230,11 +1225,11 @@ configure(rootProject) {
doFirst {
classpath = files(
// Ensure Servlet 3.x and Hibernate 4.x have precedence on the javadoc
// ensure Servlet 3.x and Hibernate 4.x have precedence on the javadoc
// classpath over their respective 2.5 and 3.x variants
project(":spring-webmvc").sourceSets.main.compileClasspath.files.find { it =~ "servlet-api" },
rootProject.sourceSets.test.compileClasspath.files.find { it =~ "hibernate-core" },
// Ensure the javadoc process can resolve types compiled from .aj sources
// ensure the javadoc process can resolve types compiled from .aj sources
project(":spring-aspects").sourceSets.main.output
)
classpath += files(subprojects.collect { it.sourceSets.main.compileClasspath })
+1 -1
View File
@@ -1 +1 @@
version=4.3.19.RELEASE
version=4.3.5.RELEASE
+2 -2
View File
@@ -29,8 +29,8 @@ def customizePom(pom, gradleProject) {
}
licenses {
license {
name "Apache License, Version 2.0"
url "http://www.apache.org/licenses/LICENSE-2.0"
name "The Apache Software License, Version 2.0"
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
distribution "repo"
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,11 +48,10 @@ import java.lang.reflect.Method;
public interface MethodMatcher {
/**
* Perform static checking whether the given method matches.
* <p>If this returns {@code false} or if the {@link #isRuntime()}
* method returns {@code false}, no runtime check (i.e. no
* {@link #matches(java.lang.reflect.Method, Class, Object[])} call)
* will be made.
* Perform static checking whether the given method matches. If this
* returns {@code false} or if the {@link #isRuntime()} method
* returns {@code false}, no runtime check (i.e. no.
* {@link #matches(java.lang.reflect.Method, Class, Object[])} call) will be made.
* @param method the candidate method
* @param targetClass the target class (may be {@code null}, in which case
* the candidate class must be taken to be the method's declaring class)
@@ -1,5 +1,5 @@
/*<
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2012 the original author 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,8 +34,9 @@ public interface TargetSource extends TargetClassAware {
/**
* Return the type of targets returned by this {@link TargetSource}.
* <p>Can return {@code null}, although certain usages of a {@code TargetSource}
* might just work with a predetermined target class.
* <p>Can return {@code null}, although certain usages of a
* {@code TargetSource} might just work with a predetermined
* target class.
* @return the type of targets returned by this {@link TargetSource}
*/
@Override
@@ -43,8 +44,9 @@ public interface TargetSource extends TargetClassAware {
/**
* Will all calls to {@link #getTarget()} return the same object?
* <p>In that case, there will be no need to invoke {@link #releaseTarget(Object)},
* and the AOP framework can cache the return value of {@link #getTarget()}.
* <p>In that case, there will be no need to invoke
* {@link #releaseTarget(Object)}, and the AOP framework can cache
* the return value of {@link #getTarget()}.
* @return {@code true} if the target is immutable
* @see #getTarget
*/
@@ -53,15 +55,14 @@ public interface TargetSource extends TargetClassAware {
/**
* Return a target instance. Invoked immediately before the
* AOP framework calls the "target" of an AOP method invocation.
* @return the target object which contains the joinpoint,
* or {@code null} if there is no actual target instance
* @return the target object, which contains the joinpoint
* @throws Exception if the target object can't be resolved
*/
Object getTarget() throws Exception;
/**
* Release the given target object obtained from the
* {@link #getTarget()} method, if any.
* {@link #getTarget()} method.
* @param target object obtained from a call to {@link #getTarget()}
* @throws Exception if the object can't be released
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -103,8 +103,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
private final AspectInstanceFactory aspectInstanceFactory;
/**
* The name of the aspect (ref bean) in which this advice was defined
* (used when determining advice precedence so that we can determine
* The name of the aspect (ref bean) in which this advice was defined (used
* when determining advice precedence so that we can determine
* whether two pieces of advice come from the same aspect).
*/
private String aspectName;
@@ -118,13 +118,13 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
* This will be non-null if the creator of this advice object knows the argument names
* and sets them explicitly
*/
private String[] argumentNames;
private String[] argumentNames = null;
/** Non-null if after throwing advice binds the thrown value */
private String throwingName;
private String throwingName = null;
/** Non-null if after returning advice binds the return value */
private String returningName;
private String returningName = null;
private Class<?> discoveredReturningType = Object.class;
@@ -227,7 +227,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
}
/**
* Set the declaration order of this advice within the aspect.
* Sets the <b>declaration order</b> of this advice within the aspect
*/
public void setDeclarationOrder(int order) {
this.declarationOrder = order;
@@ -295,8 +295,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
}
catch (Throwable ex) {
throw new IllegalArgumentException("Returning name '" + name +
"' is neither a valid argument name nor the fully-qualified " +
"name of a Java type on the classpath. Root cause: " + ex);
"' is neither a valid argument name nor the fully-qualified name of a Java type on the classpath. " +
"Root cause: " + ex);
}
}
}
@@ -329,8 +329,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
}
catch (Throwable ex) {
throw new IllegalArgumentException("Throwing name '" + name +
"' is neither a valid argument name nor the fully-qualified " +
"name of a Java type on the classpath. Root cause: " + ex);
"' is neither a valid argument name nor the fully-qualified name of a Java type on the classpath. " +
"Root cause: " + ex);
}
}
}
@@ -366,7 +366,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
* to which argument name. There are multiple strategies for determining
* this binding, which are arranged in a ChainOfResponsibility.
*/
public final synchronized void calculateArgumentBindings() {
public synchronized final void calculateArgumentBindings() {
// The simple case... nothing to bind.
if (this.argumentsIntrospected || this.parameterTypes.length == 0) {
return;
@@ -374,8 +374,10 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
int numUnboundArgs = this.parameterTypes.length;
Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0]) ||
maybeBindJoinPointStaticPart(parameterTypes[0])) {
if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0])) {
numUnboundArgs--;
}
else if (maybeBindJoinPointStaticPart(parameterTypes[0])) {
numUnboundArgs--;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -113,7 +113,6 @@ import org.springframework.util.StringUtils;
* returning {@code null} in the case that the parameter names cannot be discovered.
*
* @author Adrian Colyer
* @author Juergen Hoeller
* @since 2.0
*/
public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscoverer {
@@ -155,17 +154,23 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
/** The pointcut expression associated with the advice, as a simple String */
private String pointcutExpression;
private boolean raiseExceptions;
/** If the advice is afterReturning, and binds the return value, this is the parameter name used */
/**
* If the advice is afterReturning, and binds the return value, this is the parameter name used.
*/
private String returningName;
/** If the advice is afterThrowing, and binds the thrown value, this is the parameter name used */
/**
* If the advice is afterThrowing, and binds the thrown value, this is the parameter name used.
*/
private String throwingName;
/**
* The pointcut expression associated with the advice, as a simple String.
*/
private String pointcutExpression;
private Class<?>[] argumentTypes;
private String[] parameterNameBindings;
@@ -181,7 +186,6 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
this.pointcutExpression = pointcutExpression;
}
/**
* Indicate whether {@link IllegalArgumentException} and {@link AmbiguousBindingException}
* must be thrown as appropriate in the case of failing to deduce advice parameter names.
@@ -209,7 +213,6 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
this.throwingName = throwingName;
}
/**
* Deduce the parameter names for an advice method.
* <p>See the {@link AspectJAdviceParameterNameDiscoverer class level javadoc}
@@ -415,7 +418,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
String[] tokens = StringUtils.tokenizeToStringArray(this.pointcutExpression, " ");
for (int i = 0; i < tokens.length; i++) {
String toMatch = tokens[i];
int firstParenIndex = toMatch.indexOf('(');
int firstParenIndex = toMatch.indexOf("(");
if (firstParenIndex != -1) {
toMatch = toMatch.substring(0, firstParenIndex);
}
@@ -471,7 +474,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
* If the token starts meets Java identifier conventions, it's in.
*/
private String maybeExtractVariableName(String candidateToken) {
if (!StringUtils.hasLength(candidateToken)) {
if (candidateToken == null || candidateToken.equals("")) {
return null;
}
if (Character.isJavaIdentifierStart(candidateToken.charAt(0)) &&
@@ -575,7 +578,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
if (toMatch.startsWith("!")) {
toMatch = toMatch.substring(1);
}
int firstParenIndex = toMatch.indexOf('(');
int firstParenIndex = toMatch.indexOf("(");
if (firstParenIndex != -1) {
toMatch = toMatch.substring(0, firstParenIndex);
}
@@ -186,24 +186,13 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
throw new IllegalStateException("Must set property 'expression' before attempting to match");
}
if (this.pointcutExpression == null) {
this.pointcutClassLoader = determinePointcutClassLoader();
this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
ClassUtils.getDefaultClassLoader());
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
}
}
/**
* Determine the ClassLoader to use for pointcut evaluation.
*/
private ClassLoader determinePointcutClassLoader() {
if (this.beanFactory instanceof ConfigurableBeanFactory) {
return ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader();
}
if (this.pointcutDeclarationScope != null) {
return this.pointcutDeclarationScope.getClassLoader();
}
return ClassUtils.getDefaultClassLoader();
}
/**
* Build the underlying AspectJ pointcut expression.
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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,8 +18,6 @@ package org.springframework.aop.aspectj;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractGenericPointcutAdvisor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
/**
* Spring AOP Advisor that can be used for any AspectJ pointcut expression.
@@ -28,11 +26,16 @@ import org.springframework.beans.factory.BeanFactoryAware;
* @since 2.0
*/
@SuppressWarnings("serial")
public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor implements BeanFactoryAware {
public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor {
private final AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
public void setExpression(String expression) {
this.pointcut.setExpression(expression);
}
@@ -49,22 +52,12 @@ public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdv
return this.pointcut.getLocation();
}
public void setParameterTypes(Class<?>[] types) {
this.pointcut.setParameterTypes(types);
}
public void setParameterNames(String... names) {
this.pointcut.setParameterNames(names);
}
public void setParameterTypes(Class<?>... types) {
this.pointcut.setParameterTypes(types);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.pointcut.setBeanFactory(beanFactory);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import org.springframework.aop.Pointcut;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.core.Ordered;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* AspectJPointcutAdvisor that adapts an {@link AbstractAspectJAdvice}
@@ -50,11 +51,11 @@ public class AspectJPointcutAdvisor implements PointcutAdvisor, Ordered {
this.pointcut = advice.buildSafePointcut();
}
public void setOrder(int order) {
this.order = order;
}
@Override
public boolean isPerInstance() {
return true;
@@ -90,12 +91,12 @@ public class AspectJPointcutAdvisor implements PointcutAdvisor, Ordered {
return false;
}
AspectJPointcutAdvisor otherAdvisor = (AspectJPointcutAdvisor) other;
return this.advice.equals(otherAdvisor.advice);
return (ObjectUtils.nullSafeEquals(this.advice, otherAdvisor.advice));
}
@Override
public int hashCode() {
return AspectJPointcutAdvisor.class.hashCode() * 29 + this.advice.hashCode();
return AspectJPointcutAdvisor.class.hashCode();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2012 the original author 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 org.aopalliance.aop.Advice;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.IntroductionAdvisor;
import org.springframework.aop.IntroductionInterceptor;
import org.springframework.aop.support.ClassFilters;
import org.springframework.aop.support.DelegatePerTargetObjectIntroductionInterceptor;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
@@ -35,12 +34,12 @@ import org.springframework.aop.support.DelegatingIntroductionInterceptor;
*/
public class DeclareParentsAdvisor implements IntroductionAdvisor {
private final Advice advice;
private final Class<?> introducedInterface;
private final ClassFilter typePatternClassFilter;
private final Advice advice;
/**
* Create a new advisor for this DeclareParents field.
@@ -49,8 +48,8 @@ public class DeclareParentsAdvisor implements IntroductionAdvisor {
* @param defaultImpl the default implementation class
*/
public DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, Class<?> defaultImpl) {
this(interfaceType, typePattern,
new DelegatePerTargetObjectIntroductionInterceptor(defaultImpl, interfaceType));
this(interfaceType, typePattern, defaultImpl,
new DelegatePerTargetObjectIntroductionInterceptor(defaultImpl, interfaceType));
}
/**
@@ -60,7 +59,8 @@ public class DeclareParentsAdvisor implements IntroductionAdvisor {
* @param delegateRef the delegate implementation object
*/
public DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, Object delegateRef) {
this(interfaceType, typePattern, new DelegatingIntroductionInterceptor(delegateRef));
this(interfaceType, typePattern, delegateRef.getClass(),
new DelegatingIntroductionInterceptor(delegateRef));
}
/**
@@ -68,21 +68,23 @@ public class DeclareParentsAdvisor implements IntroductionAdvisor {
* (cannot use method such as init() to share common code, due the use of final fields)
* @param interfaceType static field defining the introduction
* @param typePattern type pattern the introduction is restricted to
* @param interceptor the delegation advice as {@link IntroductionInterceptor}
* @param implementationClass implementation class
* @param advice delegation advice
*/
private DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, IntroductionInterceptor interceptor) {
this.advice = interceptor;
private DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, Class<?> implementationClass, Advice advice) {
this.introducedInterface = interfaceType;
ClassFilter typePatternFilter = new TypePatternClassFilter(typePattern);
// Excludes methods implemented.
ClassFilter typePatternFilter = new TypePatternClassFilter(typePattern);
ClassFilter exclusion = new ClassFilter() {
@Override
public boolean matches(Class<?> clazz) {
return !introducedInterface.isAssignableFrom(clazz);
return !(introducedInterface.isAssignableFrom(clazz));
}
};
this.typePatternClassFilter = ClassFilters.intersection(typePatternFilter, exclusion);
this.advice = advice;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,15 +32,17 @@ import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.util.Assert;
/**
* An implementation of the AspectJ {@link ProceedingJoinPoint} interface
* wrapping an AOP Alliance {@link org.aopalliance.intercept.MethodInvocation}.
* Implementation of AspectJ ProceedingJoinPoint interface
* wrapping an AOP Alliance MethodInvocation.
*
* <p><b>Note</b>: The {@code getThis()} method returns the current Spring AOP proxy.
* <p><b>Note</b>: the {@code getThis()} method returns the current Spring AOP proxy.
* The {@code getTarget()} method returns the current Spring AOP target (which may be
* {@code null} if there is no target instance) as a plain POJO without any advice.
* <b>If you want to call the object and have the advice take effect, use {@code getThis()}.</b>
* A common example is casting the object to an introduced interface in the implementation of
* an introduction. There is no such distinction between target and proxy in AspectJ itself.
* {@code null} if there is no target), and is a plain POJO without any advice.
* <b>If you want to call the object and have the advice take effect, use
* {@code getThis()}.</b> A common example is casting the object to an
* introduced interface in the implementation of an introduction.
*
* <p>Of course there is no such distinction between target and proxy in AspectJ.
*
* @author Rod Johnson
* @author Juergen Hoeller
@@ -54,7 +56,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
private final ProxyMethodInvocation methodInvocation;
private Object[] args;
private Object[] defensiveCopyOfArgs;
/** Lazily initialized signature object */
private Signature signature;
@@ -73,7 +75,6 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
this.methodInvocation = methodInvocation;
}
@Override
public void set$AroundClosure(AroundClosure aroundClosure) {
throw new UnsupportedOperationException();
@@ -114,10 +115,12 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
@Override
public Object[] getArgs() {
if (this.args == null) {
this.args = this.methodInvocation.getArguments().clone();
if (this.defensiveCopyOfArgs == null) {
Object[] argsSource = this.methodInvocation.getArguments();
this.defensiveCopyOfArgs = new Object[argsSource.length];
System.arraycopy(argsSource, 0, this.defensiveCopyOfArgs, 0, argsSource.length);
}
return this.args;
return this.defensiveCopyOfArgs;
}
@Override
@@ -125,7 +128,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
if (this.signature == null) {
this.signature = new MethodSignatureImpl();
}
return this.signature;
return signature;
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,7 +41,6 @@ public class SimpleAspectInstanceFactory implements AspectInstanceFactory {
this.aspectClass = aspectClass;
}
/**
* Return the specified aspect class (never {@code null}).
*/
@@ -49,6 +48,7 @@ public class SimpleAspectInstanceFactory implements AspectInstanceFactory {
return this.aspectClass;
}
@Override
public final Object getAspectInstance() {
try {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,7 +27,6 @@ import org.springframework.util.StringUtils;
* Spring AOP {@link ClassFilter} implementation using AspectJ type matching.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 2.0
*/
public class TypePatternClassFilter implements ClassFilter {
@@ -77,21 +76,17 @@ public class TypePatternClassFilter implements ClassFilter {
* or is recognized as invalid
*/
public void setTypePattern(String typePattern) {
Assert.notNull(typePattern, "Type pattern must not be null");
Assert.notNull(typePattern);
this.typePattern = typePattern;
this.aspectJTypePatternMatcher =
PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution().
parseTypePattern(replaceBooleanOperators(typePattern));
}
/**
* Return the AspectJ type pattern to match.
*/
public String getTypePattern() {
return this.typePattern;
return typePattern;
}
/**
* Should the pointcut apply to the given interface or target class?
* @param clazz candidate target class
@@ -100,7 +95,9 @@ public class TypePatternClassFilter implements ClassFilter {
*/
@Override
public boolean matches(Class<?> clazz) {
Assert.state(this.aspectJTypePatternMatcher != null, "No type pattern has been set");
if (this.aspectJTypePatternMatcher == null) {
throw new IllegalStateException("No 'typePattern' has been set via ctor/setter.");
}
return this.aspectJTypePatternMatcher.matches(clazz);
}
@@ -111,8 +108,9 @@ public class TypePatternClassFilter implements ClassFilter {
* <p>This method converts back to {@code &&} for the AspectJ pointcut parser.
*/
private String replaceBooleanOperators(String pcExpr) {
String result = StringUtils.replace(pcExpr," and "," && ");
result = StringUtils.replace(result, " or ", " || ");
return StringUtils.replace(result, " not ", " ! ");
pcExpr = StringUtils.replace(pcExpr," and "," && ");
pcExpr = StringUtils.replace(pcExpr, " or ", " || ");
pcExpr = StringUtils.replace(pcExpr, " not ", " ! ");
return pcExpr;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,6 +38,7 @@ import org.aspectj.lang.reflect.AjType;
import org.aspectj.lang.reflect.AjTypeSystem;
import org.aspectj.lang.reflect.PerClauseKind;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
@@ -59,9 +60,6 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
private static final String AJC_MAGIC = "ajc$";
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
@@ -123,14 +121,59 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
}
}
/**
* The pointcut and advice annotations both have an "argNames" member which contains a
* comma-separated list of the argument names. We use this (if non-empty) to build the
* formal parameters for the pointcut.
*/
protected AspectJExpressionPointcut createPointcutExpression(
Method annotatedMethod, Class<?> declarationScope, String[] pointcutParameterNames) {
Class<?> [] pointcutParameterTypes = new Class<?>[0];
if (pointcutParameterNames != null) {
pointcutParameterTypes = extractPointcutParameterTypes(pointcutParameterNames,annotatedMethod);
}
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(declarationScope,pointcutParameterNames,pointcutParameterTypes);
ajexp.setLocation(annotatedMethod.toString());
return ajexp;
}
/**
* Create the pointcut parameters needed by aspectj based on the given argument names
* and the argument types that are available from the adviceMethod. Needs to take into
* account (ignore) any JoinPoint based arguments as these are not pointcut context but
* rather part of the advice execution context (thisJoinPoint, thisJoinPointStaticPart)
*/
private Class<?>[] extractPointcutParameterTypes(String[] argNames, Method adviceMethod) {
Class<?>[] ret = new Class<?>[argNames.length];
Class<?>[] paramTypes = adviceMethod.getParameterTypes();
if (argNames.length > paramTypes.length) {
throw new IllegalStateException("Expecting at least " + argNames.length +
" arguments in the advice declaration, but only found " + paramTypes.length);
}
// Make the simplifying assumption for now that all of the JoinPoint based arguments
// come first in the advice declaration.
int typeOffset = paramTypes.length - argNames.length;
for (int i = 0; i < ret.length; i++) {
ret[i] = paramTypes[i + typeOffset];
}
return ret;
}
/**
* Find and return the first AspectJ annotation on the given method
* (there <i>should</i> only be one anyway...).
* (there <i>should</i> only be one anyway...)
*/
@SuppressWarnings("unchecked")
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
Class<?>[] classesToLookFor = new Class<?>[] {
Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
for (Class<?> c : classesToLookFor) {
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
if (foundAnnotation != null) {
return foundAnnotation;
}
@@ -149,13 +192,14 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
}
/**
* Enum for AspectJ annotation types.
* @see AspectJAnnotation#getAnnotationType()
*/
protected enum AspectJAnnotationType {
AtPointcut, AtAround, AtBefore, AtAfter, AtAfterReturning, AtAfterThrowing
AtPointcut,
AtBefore,
AtAfter,
AtAfterReturning,
AtAfterThrowing,
AtAround
}
@@ -165,18 +209,18 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
*/
protected static class AspectJAnnotation<A extends Annotation> {
private static final String[] EXPRESSION_ATTRIBUTES = new String[] {"pointcut", "value"};
private static final String[] EXPRESSION_PROPERTIES = new String[] {"value", "pointcut"};
private static Map<Class<?>, AspectJAnnotationType> annotationTypeMap =
new HashMap<Class<?>, AspectJAnnotationType>(8);
private static Map<Class<?>, AspectJAnnotationType> annotationTypes =
new HashMap<Class<?>, AspectJAnnotationType>();
static {
annotationTypeMap.put(Pointcut.class, AspectJAnnotationType.AtPointcut);
annotationTypeMap.put(Around.class, AspectJAnnotationType.AtAround);
annotationTypeMap.put(Before.class, AspectJAnnotationType.AtBefore);
annotationTypeMap.put(After.class, AspectJAnnotationType.AtAfter);
annotationTypeMap.put(AfterReturning.class, AspectJAnnotationType.AtAfterReturning);
annotationTypeMap.put(AfterThrowing.class, AspectJAnnotationType.AtAfterThrowing);
annotationTypes.put(Pointcut.class,AspectJAnnotationType.AtPointcut);
annotationTypes.put(After.class,AspectJAnnotationType.AtAfter);
annotationTypes.put(AfterReturning.class,AspectJAnnotationType.AtAfterReturning);
annotationTypes.put(AfterThrowing.class,AspectJAnnotationType.AtAfterThrowing);
annotationTypes.put(Around.class,AspectJAnnotationType.AtAround);
annotationTypes.put(Before.class,AspectJAnnotationType.AtBefore);
}
private final A annotation;
@@ -190,31 +234,44 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
public AspectJAnnotation(A annotation) {
this.annotation = annotation;
this.annotationType = determineAnnotationType(annotation);
// We know these methods exist with the same name on each object,
// but need to invoke them reflectively as there isn't a common interface.
try {
this.pointcutExpression = resolveExpression(annotation);
this.argumentNames = (String) AnnotationUtils.getValue(annotation, "argNames");
this.argumentNames = (String) annotation.getClass().getMethod("argNames").invoke(annotation);
}
catch (Exception ex) {
throw new IllegalArgumentException(annotation + " is not a valid AspectJ annotation", ex);
throw new IllegalArgumentException(annotation + " cannot be an AspectJ annotation", ex);
}
}
private AspectJAnnotationType determineAnnotationType(A annotation) {
AspectJAnnotationType type = annotationTypeMap.get(annotation.annotationType());
if (type != null) {
return type;
}
throw new IllegalStateException("Unknown annotation type: " + annotation);
}
private String resolveExpression(A annotation) {
for (String attributeName : EXPRESSION_ATTRIBUTES) {
String candidate = (String) AnnotationUtils.getValue(annotation, attributeName);
if (StringUtils.hasText(candidate)) {
return candidate;
for (Class<?> type : annotationTypes.keySet()) {
if (type.isInstance(annotation)) {
return annotationTypes.get(type);
}
}
throw new IllegalStateException("Failed to resolve expression: " + annotation);
throw new IllegalStateException("Unknown annotation type: " + annotation.toString());
}
private String resolveExpression(A annotation) throws Exception {
String expression = null;
for (String methodName : EXPRESSION_PROPERTIES) {
Method method;
try {
method = annotation.getClass().getDeclaredMethod(methodName);
}
catch (NoSuchMethodException ex) {
method = null;
}
if (method != null) {
String candidate = (String) method.invoke(annotation);
if (StringUtils.hasText(candidate)) {
expression = candidate;
}
}
}
return expression;
}
public AspectJAnnotationType getAnnotationType() {
@@ -255,11 +312,11 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
if (annotation == null) {
return null;
}
StringTokenizer nameTokens = new StringTokenizer(annotation.getArgumentNames(), ",");
if (nameTokens.countTokens() > 0) {
String[] names = new String[nameTokens.countTokens()];
StringTokenizer strTok = new StringTokenizer(annotation.getArgumentNames(), ",");
if (strTok.countTokens() > 0) {
String[] names = new String[strTok.countTokens()];
for (int i = 0; i < names.length; i++) {
names[i] = nameTokens.nextToken();
names[i] = strTok.nextToken();
}
return names;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,7 +50,7 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
private List<Pattern> includePatterns;
private AspectJAdvisorFactory aspectJAdvisorFactory;
private AspectJAdvisorFactory aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory();
private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;
@@ -74,9 +74,6 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
if (this.aspectJAdvisorFactory == null) {
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
@@ -133,7 +130,6 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
public BeanFactoryAspectJAdvisorsBuilderAdapter(
ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
super(beanFactory, advisorFactory);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,9 +16,9 @@
package org.springframework.aop.aspectj.annotation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.aspectj.lang.reflect.PerClauseKind;
@@ -50,7 +50,7 @@ import org.springframework.util.ClassUtils;
public class AspectJProxyFactory extends ProxyCreatorSupport {
/** Cache for singleton aspect instances */
private static final Map<Class<?>, Object> aspectCache = new ConcurrentHashMap<Class<?>, Object>();
private static final Map<Class<?>, Object> aspectCache = new HashMap<Class<?>, Object>();
private final AspectJAdvisorFactory aspectFactory = new ReflectiveAspectJAdvisorFactory();
@@ -144,7 +144,7 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
private MetadataAwareAspectInstanceFactory createAspectInstanceFactory(
AspectMetadata am, Class<?> aspectClass, String aspectName) {
MetadataAwareAspectInstanceFactory instanceFactory;
MetadataAwareAspectInstanceFactory instanceFactory = null;
if (am.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// Create a shared aspect instance.
Object instance = getSingletonAspectInstance(aspectClass);
@@ -162,29 +162,23 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
* is created if one cannot be found in the instance cache.
*/
private Object getSingletonAspectInstance(Class<?> aspectClass) {
// Quick check without a lock...
Object instance = aspectCache.get(aspectClass);
if (instance == null) {
synchronized (aspectCache) {
// To be safe, check within full lock now...
instance = aspectCache.get(aspectClass);
if (instance == null) {
try {
instance = aspectClass.newInstance();
aspectCache.put(aspectClass, instance);
}
catch (InstantiationException ex) {
throw new AopConfigException(
"Unable to instantiate aspect class: " + aspectClass.getName(), ex);
}
catch (IllegalAccessException ex) {
throw new AopConfigException(
"Could not access aspect constructor: " + aspectClass.getName(), ex);
}
}
synchronized (aspectCache) {
Object instance = aspectCache.get(aspectClass);
if (instance != null) {
return instance;
}
try {
instance = aspectClass.newInstance();
aspectCache.put(aspectClass, instance);
return instance;
}
catch (InstantiationException ex) {
throw new AopConfigException("Unable to instantiate aspect class [" + aspectClass.getName() + "]", ex);
}
catch (IllegalAccessException ex) {
throw new AopConfigException("Cannot access aspect class [" + aspectClass.getName() + "]", ex);
}
}
return instance;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,8 +35,9 @@ import org.springframework.aop.support.ComposablePointcut;
* Metadata for an AspectJ aspect class, with an additional Spring AOP pointcut
* for the per clause.
*
* <p>Uses AspectJ 5 AJType reflection API, enabling us to work with different
* AspectJ instantiation models such as "singleton", "pertarget" and "perthis".
* <p>Uses AspectJ 5 AJType reflection API, so is only supported on Java 5.
* Enables us to work with different AspectJ instantiation models such as
* "singleton", "pertarget" and "perthis".
*
* @author Rod Johnson
* @author Juergen Hoeller
@@ -101,22 +102,20 @@ public class AspectMetadata implements Serializable {
this.ajType = ajType;
switch (this.ajType.getPerClause().getKind()) {
case SINGLETON:
case SINGLETON :
this.perClausePointcut = Pointcut.TRUE;
return;
case PERTARGET:
case PERTHIS:
case PERTARGET : case PERTHIS :
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setLocation(aspectClass.getName());
ajexp.setLocation("@Aspect annotation on " + aspectClass.getName());
ajexp.setExpression(findPerClause(aspectClass));
ajexp.setPointcutDeclarationScope(aspectClass);
this.perClausePointcut = ajexp;
return;
case PERTYPEWITHIN:
case PERTYPEWITHIN :
// Works with a type pattern
this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass)));
return;
default:
default :
throw new AopConfigException(
"PerClause " + ajType.getPerClause().getKind() + " not supported by Spring AOP for " + aspectClass);
}
@@ -126,8 +125,10 @@ public class AspectMetadata implements Serializable {
* Extract contents from String of form {@code pertarget(contents)}.
*/
private String findPerClause(Class<?> aspectClass) {
// TODO when AspectJ provides this, we can remove this hack. Hence we don't
// bother to make it elegant. Or efficient. Or robust :-)
String str = aspectClass.getAnnotation(Aspect.class).value();
str = str.substring(str.indexOf('(') + 1);
str = str.substring(str.indexOf("(") + 1);
str = str.substring(0, str.length() - 1);
return str;
}
@@ -148,7 +149,7 @@ public class AspectMetadata implements Serializable {
}
/**
* Return the aspect name.
* Return the aspect class.
*/
public String getAspectName() {
return this.aspectName;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2008 the original author 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,10 +17,10 @@
package org.springframework.aop.aspectj.annotation;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.aspectj.lang.reflect.PerClauseKind;
@@ -43,12 +43,12 @@ public class BeanFactoryAspectJAdvisorsBuilder {
private final AspectJAdvisorFactory advisorFactory;
private volatile List<String> aspectBeanNames;
private List<String> aspectBeanNames;
private final Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<String, List<Advisor>>();
private final Map<String, List<Advisor>> advisorsCache = new HashMap<String, List<Advisor>>();
private final Map<String, MetadataAwareAspectInstanceFactory> aspectFactoryCache =
new ConcurrentHashMap<String, MetadataAwareAspectInstanceFactory>();
new HashMap<String, MetadataAwareAspectInstanceFactory>();
/**
@@ -56,7 +56,7 @@ public class BeanFactoryAspectJAdvisorsBuilder {
* @param beanFactory the ListableBeanFactory to scan
*/
public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory) {
this(beanFactory, new ReflectiveAspectJAdvisorFactory(beanFactory));
this(beanFactory, new ReflectiveAspectJAdvisorFactory());
}
/**
@@ -80,57 +80,56 @@ public class BeanFactoryAspectJAdvisorsBuilder {
* @see #isEligibleBean
*/
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
List<String> aspectNames = null;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();
String[] beanNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this
// case they would be cached by the Spring container but would not
// have been weaved
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -109,40 +109,14 @@ class InstantiationModelAwarePointcutAdvisorImpl
/**
* The pointcut for Spring AOP to use.
* Actual behaviour of the pointcut will change depending on the state of the advice.
* The pointcut for Spring AOP to use. Actual behaviour of the pointcut will change
* depending on the state of the advice.
*/
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
@Override
public boolean isLazy() {
return this.lazy;
}
@Override
public synchronized boolean isAdviceInstantiated() {
return (this.instantiatedAdvice != null);
}
/**
* Lazily instantiate advice if necessary.
*/
@Override
public synchronized Advice getAdvice() {
if (this.instantiatedAdvice == null) {
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
return this.instantiatedAdvice;
}
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
}
/**
* This is only of interest for Spring AOP: AspectJ instantiation semantics
* are much richer. In AspectJ terminology, all a return of {@code true}
@@ -160,6 +134,33 @@ class InstantiationModelAwarePointcutAdvisorImpl
return this.aspectInstanceFactory.getAspectMetadata();
}
/**
* Lazily instantiate advice if necessary.
*/
@Override
public synchronized Advice getAdvice() {
if (this.instantiatedAdvice == null) {
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
return this.instantiatedAdvice;
}
@Override
public boolean isLazy() {
return this.lazy;
}
@Override
public synchronized boolean isAdviceInstantiated() {
return (this.instantiatedAdvice != null);
}
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
}
public MetadataAwareAspectInstanceFactory getAspectInstanceFactory() {
return this.aspectInstanceFactory;
}
@@ -212,26 +213,33 @@ class InstantiationModelAwarePointcutAdvisorImpl
}
else {
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
case AtAround:
this.isBeforeAdvice = false;
this.isAfterAdvice = false;
break;
case AtBefore:
this.isBeforeAdvice = true;
this.isAfterAdvice = false;
break;
case AtAfter:
case AtAfterReturning:
case AtAfterThrowing:
this.isBeforeAdvice = false;
this.isAfterAdvice = true;
this.isBeforeAdvice = false;
break;
case AtAround:
case AtPointcut:
this.isAfterAdvice = false;
this.isBeforeAdvice = false;
break;
case AtBefore:
this.isAfterAdvice = false;
this.isBeforeAdvice = true;
}
}
}
@Override
public String toString() {
return "InstantiationModelAwarePointcutAdvisor: expression [" + getDeclaredPointcut().getExpression() +
"]; advice method [" + this.aspectJAdviceMethod + "]; perClauseKind=" +
this.aspectInstanceFactory.getAspectMetadata().getAjType().getPerClause().getKind();
}
private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
inputStream.defaultReadObject();
try {
@@ -242,18 +250,11 @@ class InstantiationModelAwarePointcutAdvisorImpl
}
}
@Override
public String toString() {
return "InstantiationModelAwarePointcutAdvisor: expression [" + getDeclaredPointcut().getExpression() +
"]; advice method [" + this.aspectJAdviceMethod + "]; perClauseKind=" +
this.aspectInstanceFactory.getAspectMetadata().getAjType().getPerClause().getKind();
}
/**
* Pointcut implementation that changes its behaviour when the advice is instantiated.
* Note that this is a <i>dynamic</i> pointcut; otherwise it might be optimized out
* if it does not at first match statically.
* Note that this is a <i>dynamic</i> pointcut. Otherwise it might
* be optimized out if it does not at first match statically.
*/
private class PerTargetInstantiationModelPointcut extends DynamicMethodMatcherPointcut {
@@ -263,9 +264,8 @@ class InstantiationModelAwarePointcutAdvisorImpl
private LazySingletonAspectInstanceFactoryDecorator aspectInstanceFactory;
public PerTargetInstantiationModelPointcut(AspectJExpressionPointcut declaredPointcut,
private PerTargetInstantiationModelPointcut(AspectJExpressionPointcut declaredPointcut,
Pointcut preInstantiationPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
this.declaredPointcut = declaredPointcut;
this.preInstantiationPointcut = preInstantiationPointcut;
if (aspectInstanceFactory instanceof LazySingletonAspectInstanceFactoryDecorator) {
@@ -275,8 +275,7 @@ class InstantiationModelAwarePointcutAdvisorImpl
@Override
public boolean matches(Method method, Class<?> targetClass) {
// We're either instantiated and matching on declared pointcut,
// or uninstantiated matching on either pointcut...
// We're either instantiated and matching on declared pointcut, or uninstantiated matching on either pointcut
return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass)) ||
this.preInstantiationPointcut.getMethodMatcher().matches(method, targetClass);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,9 +20,9 @@ import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import org.aopalliance.aop.Advice;
@@ -46,7 +46,6 @@ import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice;
import org.springframework.aop.aspectj.DeclareParentsAdvisor;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConvertingComparator;
@@ -96,30 +95,6 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
}
private final BeanFactory beanFactory;
/**
* Create a new {@code ReflectiveAspectJAdvisorFactory}.
*/
public ReflectiveAspectJAdvisorFactory() {
this(null);
}
/**
* Create a new {@code ReflectiveAspectJAdvisorFactory}, propagating the given
* {@link BeanFactory} to the created {@link AspectJExpressionPointcut} instances,
* for bean pointcut handling as well as consistent {@link ClassLoader} resolution.
* @param beanFactory the BeanFactory to propagate (may be {@code null}}
* @since 4.3.6
* @see AspectJExpressionPointcut#setBeanFactory
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#getBeanClassLoader()
*/
public ReflectiveAspectJAdvisorFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
@@ -131,7 +106,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<Advisor>();
List<Advisor> advisors = new LinkedList<Advisor>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
@@ -157,7 +132,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
}
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
final List<Method> methods = new ArrayList<Method>();
final List<Method> methods = new LinkedList<Method>();
ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException {
@@ -176,7 +151,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
* for the given introduction field.
* <p>Resulting Advisors will need to be evaluated for targets.
* @param introductionField the field to introspect
* @return the Advisor instance, or {@code null} if not an Advisor
* @return {@code null} if not an Advisor
*/
private Advisor getDeclareParentsAdvisor(Field introductionField) {
DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class);
@@ -186,7 +161,9 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
}
if (DeclareParents.class == declareParents.defaultImpl()) {
throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents");
// This is what comes back if it wasn't set. This seems bizarre...
// TODO this restriction possibly should be relaxed
throw new IllegalStateException("defaultImpl must be set on DeclareParents");
}
return new DeclareParentsAdvisor(
@@ -220,7 +197,6 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
ajexp.setBeanFactory(this.beanFactory);
return ajexp;
}
@@ -253,15 +229,6 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
@@ -286,6 +253,15 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
@@ -299,7 +275,6 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,10 +31,11 @@ import org.springframework.util.Assert;
/**
* Utility class for handling registration of AOP auto-proxy creators.
*
* <p>Only a single auto-proxy creator should be registered yet multiple concrete
* implementations are available. This class provides a simple escalation protocol,
* allowing a caller to request a particular auto-proxy creator and know that creator,
* <i>or a more capable variant thereof</i>, will be registered as a post-processor.
* <p>Only a single auto-proxy creator can be registered yet multiple concrete
* implementations are available. Therefore this class wraps a simple escalation
* protocol, allowing classes to request a particular auto-proxy creator and know
* that class, {@code or a subclass thereof}, will eventually be resident
* in the application context.
*
* @author Rob Harrop
* @author Juergen Hoeller
@@ -53,10 +54,12 @@ public abstract class AopConfigUtils {
/**
* Stores the auto proxy creator classes in escalation order.
*/
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<Class<?>>(3);
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<Class<?>>();
/**
* Setup the escalation list.
*/
static {
// Set up the escalation list...
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
@@ -104,7 +107,6 @@ public abstract class AopConfigUtils {
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
@@ -116,7 +118,6 @@ public abstract class AopConfigUtils {
}
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2013 the original author 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,11 +27,11 @@ import org.springframework.beans.factory.xml.ParserContext;
* Utility class for handling registration of auto-proxy creators used internally
* by the '{@code aop}' namespace tags.
*
* <p>Only a single auto-proxy creator should be registered and multiple configuration
* elements may wish to register different concrete implementations. As such this class
* delegates to {@link AopConfigUtils} which provides a simple escalation protocol.
* Callers may request a particular auto-proxy creator and know that creator,
* <i>or a more capable variant thereof</i>, will be registered as a post-processor.
* <p>Only a single auto-proxy creator can be registered and multiple tags may wish
* to register different concrete implementations. As such this class delegates to
* {@link AopConfigUtils} which wraps a simple escalation protocol. Therefore classes
* may request a particular auto-proxy creator and know that class, <i>or a subclass
* thereof</i>, will eventually be resident in the application context.
*
* @author Rob Harrop
* @author Juergen Hoeller
@@ -81,11 +81,11 @@ public abstract class AopNamespaceUtils {
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
if (sourceElement != null) {
boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
@@ -94,8 +94,9 @@ public abstract class AopNamespaceUtils {
private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ParserContext parserContext) {
if (beanDefinition != null) {
parserContext.registerComponent(
new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME));
BeanComponentDefinition componentDefinition =
new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
parserContext.registerComponent(componentDefinition);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2012 the original author 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,8 +21,8 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.Ordered;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Implementation of {@link AspectInstanceFactory} that locates the aspect from the
@@ -50,7 +50,9 @@ public class SimpleBeanFactoryAwareAspectInstanceFactory implements AspectInstan
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
Assert.notNull(this.aspectBeanName, "'aspectBeanName' is required");
if (!StringUtils.hasText(this.aspectBeanName)) {
throw new IllegalArgumentException("'aspectBeanName' is required");
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -90,7 +90,7 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSu
return proxyFactory.getProxy(getProxyClassLoader());
}
// No proxy needed.
// No async proxy needed.
return bean;
}
@@ -155,7 +155,7 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSu
* Subclasses may choose to implement this: for example,
* to change the interfaces exposed.
* <p>The default implementation is empty.
* @param proxyFactory the ProxyFactory that is already configured with
* @param proxyFactory ProxyFactory that is already configured with
* target, advisor and interfaces and will be used to create the proxy
* immediately after this method returns
* @since 4.2.3
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -92,7 +93,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
* List of Advisors. If an Advice is added, it will be wrapped
* in an Advisor before being added to this List.
*/
private List<Advisor> advisors = new ArrayList<Advisor>();
private List<Advisor> advisors = new LinkedList<Advisor>();
/**
* Array updated on changes to the advisors list, which is easier
@@ -233,7 +234,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
@Override
public Class<?>[] getProxiedInterfaces() {
return ClassUtils.toClassArray(this.interfaces);
return this.interfaces.toArray(new Class<?>[this.interfaces.size()]);
}
@Override
@@ -479,7 +480,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
* for the given method, based on this configuration.
* @param method the proxied method
* @param targetClass the target class
* @return a List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
* @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
*/
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
@@ -533,7 +534,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
/**
* Build a configuration-only copy of this AdvisedSupport,
* replacing the TargetSource.
* replacing the TargetSource
*/
AdvisedSupport getConfigurationOnlyCopy() {
AdvisedSupport copy = new AdvisedSupport();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,25 +43,6 @@ import org.springframework.util.ObjectUtils;
*/
public abstract class AopProxyUtils {
/**
* Obtain the singleton target object behind the given proxy, if any.
* @param candidate the (potential) proxy to check
* @return the singleton target object managed in a {@link SingletonTargetSource},
* or {@code null} in any other case (not a proxy, not an existing singleton target)
* @since 4.3.8
* @see Advised#getTargetSource()
* @see SingletonTargetSource#getTarget()
*/
public static Object getSingletonTarget(Object candidate) {
if (candidate instanceof Advised) {
TargetSource targetSource = ((Advised) candidate).getTargetSource();
if (targetSource instanceof SingletonTargetSource) {
return ((SingletonTargetSource) targetSource).getTarget();
}
}
return null;
}
/**
* Determine the ultimate target class of the given bean instance, traversing
* not only a top-level proxy but any number of nested proxies as well &mdash;
@@ -78,7 +59,14 @@ public abstract class AopProxyUtils {
Class<?> result = null;
while (current instanceof TargetClassAware) {
result = ((TargetClassAware) current).getTargetClass();
current = getSingletonTarget(current);
Object nested = null;
if (current instanceof Advised) {
TargetSource targetSource = ((Advised) current).getTargetSource();
if (targetSource instanceof SingletonTargetSource) {
nested = ((SingletonTargetSource) targetSource).getTarget();
}
}
current = nested;
}
if (result == null) {
result = (AopUtils.isCglibProxy(candidate) ? candidate.getClass().getSuperclass() : candidate.getClass());
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,7 +23,6 @@ import java.lang.reflect.UndeclaredThrowableException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import org.aopalliance.aop.Advice;
@@ -57,6 +56,9 @@ import org.springframework.util.ObjectUtils;
/**
* CGLIB-based {@link AopProxy} implementation for the Spring AOP framework.
*
* <p>Formerly named {@code Cglib2AopProxy}, as of Spring 3.2, this class depends on
* Spring's own internally repackaged version of CGLIB 3.</i>.
*
* <p>Objects of this type should be obtained through proxy factories,
* configured by an {@link AdvisedSupport} object. This class is internal
* to Spring's AOP framework and need not be used directly by client code.
@@ -201,16 +203,18 @@ class CglibAopProxy implements AopProxy, Serializable {
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
catch (Exception ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
@@ -237,11 +241,10 @@ class CglibAopProxy implements AopProxy, Serializable {
* validates it if not.
*/
private void validateClassIfNecessary(Class<?> proxySuperClass, ClassLoader proxyClassLoader) {
if (logger.isWarnEnabled()) {
if (logger.isInfoEnabled()) {
synchronized (validatedClasses) {
if (!validatedClasses.containsKey(proxySuperClass)) {
doValidateClass(proxySuperClass, proxyClassLoader,
ClassUtils.getAllInterfacesForClassAsSet(proxySuperClass));
doValidateClass(proxySuperClass, proxyClassLoader);
validatedClasses.put(proxySuperClass, Boolean.TRUE);
}
}
@@ -252,35 +255,30 @@ class CglibAopProxy implements AopProxy, Serializable {
* Checks for final methods on the given {@code Class}, as well as package-visible
* methods across ClassLoaders, and writes warnings to the log for each one found.
*/
private void doValidateClass(Class<?> proxySuperClass, ClassLoader proxyClassLoader, Set<Class<?>> ifcs) {
if (proxySuperClass != Object.class) {
private void doValidateClass(Class<?> proxySuperClass, ClassLoader proxyClassLoader) {
if (Object.class != proxySuperClass) {
Method[] methods = proxySuperClass.getDeclaredMethods();
for (Method method : methods) {
int mod = method.getModifiers();
if (!Modifier.isStatic(mod) && !Modifier.isPrivate(mod)) {
if (!Modifier.isStatic(mod)) {
if (Modifier.isFinal(mod)) {
if (implementsInterface(method, ifcs)) {
logger.warn("Unable to proxy interface-implementing method [" + method + "] because " +
"it is marked as final: Consider using interface-based JDK proxies instead!");
}
logger.info("Final method [" + method + "] cannot get proxied via CGLIB: " +
"Calls to this method will NOT be routed to the target instance and " +
"might lead to NPEs against uninitialized fields in the proxy instance.");
logger.info("Unable to proxy method [" + method + "] because it is final: " +
"All calls to this method via a proxy will NOT be routed to the target instance.");
}
else if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod) &&
else if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod) && !Modifier.isPrivate(mod) &&
proxyClassLoader != null && proxySuperClass.getClassLoader() != proxyClassLoader) {
logger.info("Method [" + method + "] is package-visible across different ClassLoaders " +
"and cannot get proxied via CGLIB: Declare this method as public or protected " +
"if you need to support invocations through the proxy.");
logger.info("Unable to proxy method [" + method + "] because it is package-visible " +
"across different ClassLoaders: All calls to this method via a proxy will " +
"NOT be routed to the target instance.");
}
}
}
doValidateClass(proxySuperClass.getSuperclass(), proxyClassLoader, ifcs);
doValidateClass(proxySuperClass.getSuperclass(), proxyClassLoader);
}
}
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Parameters used for optimization choices...
// Parameters used for optimisation choices...
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
@@ -292,20 +290,20 @@ class CglibAopProxy implements AopProxy, Serializable {
// unadvised but can return this). May be required to expose the proxy.
Callback targetInterceptor;
if (exposeProxy) {
targetInterceptor = (isStatic ?
targetInterceptor = isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
}
else {
targetInterceptor = (isStatic ?
targetInterceptor = isStatic ?
new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
}
// Choose a "direct to target" dispatcher (used for
// unadvised calls to static targets that cannot return this).
Callback targetDispatcher = (isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());
Callback targetDispatcher = isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();
Callback[] mainCallbacks = new Callback[] {
aopInterceptor, // for normal advice
@@ -319,14 +317,14 @@ class CglibAopProxy implements AopProxy, Serializable {
Callback[] callbacks;
// If the target is a static one and the advice chain is frozen,
// then we can make some optimizations by sending the AOP calls
// then we can make some optimisations by sending the AOP calls
// direct to the target using the fixed chain for that method.
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);
// TODO: small memory optimization here (can skip creation for methods with no advice)
// TODO: small memory optimisation here (can skip creation for methods with no advice)
for (int x = 0; x < methods.length; x++) {
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
@@ -347,31 +345,6 @@ class CglibAopProxy implements AopProxy, Serializable {
return callbacks;
}
@Override
public boolean equals(Object other) {
return (this == other || (other instanceof CglibAopProxy &&
AopProxyUtils.equalsInProxy(this.advised, ((CglibAopProxy) other).advised)));
}
@Override
public int hashCode() {
return CglibAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();
}
/**
* Check whether the given method is declared on any of the given interfaces.
*/
private static boolean implementsInterface(Method method, Set<Class<?>> ifcs) {
for (Class<?> ifc : ifcs) {
if (ClassUtils.hasMethod(ifc, method.getName(), method.getParameterTypes())) {
return true;
}
}
return false;
}
/**
* Process a return value. Wraps a return of {@code this} if necessary to be the
* {@code proxy} and also verifies that {@code null} is not returned as a primitive.
@@ -393,6 +366,18 @@ class CglibAopProxy implements AopProxy, Serializable {
}
@Override
public boolean equals(Object other) {
return (this == other || (other instanceof CglibAopProxy &&
AopProxyUtils.equalsInProxy(this.advised, ((CglibAopProxy) other).advised)));
}
@Override
public int hashCode() {
return CglibAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();
}
/**
* Serializable replacement for CGLIB's NoOp interface.
* Public to allow use elsewhere in the framework.
@@ -810,16 +795,12 @@ class CglibAopProxy implements AopProxy, Serializable {
}
// We must always proxy equals, to direct calls to this.
if (AopUtils.isEqualsMethod(method)) {
if (logger.isDebugEnabled()) {
logger.debug("Found 'equals' method: " + method);
}
logger.debug("Found 'equals' method: " + method);
return INVOKE_EQUALS;
}
// We must always calculate hashCode based on the proxy.
if (AopUtils.isHashCodeMethod(method)) {
if (logger.isDebugEnabled()) {
logger.debug("Found 'hashCode' method: " + method);
}
logger.debug("Found 'hashCode' method: " + method);
return INVOKE_HASHCODE;
}
Class<?> targetClass = this.advised.getTargetClass();
@@ -842,43 +823,52 @@ class CglibAopProxy implements AopProxy, Serializable {
// Else use the AOP_PROXY.
if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {
if (logger.isDebugEnabled()) {
logger.debug("Method has advice and optimizations are enabled: " + method);
logger.debug("Method has advice and optimisations are enabled: " + method);
}
// We know that we are optimizing so we can use the FixedStaticChainInterceptors.
// We know that we are optimising so we can use the FixedStaticChainInterceptors.
int index = this.fixedInterceptorMap.get(key);
return (index + this.fixedInterceptorOffset);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Unable to apply any optimizations to advised method: " + method);
logger.debug("Unable to apply any optimisations to advised method: " + method);
}
return AOP_PROXY;
}
}
else {
// See if the return type of the method is outside the class hierarchy 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, then we cannot use a dispatcher because the
// target needs to be explicitly released after the invocation.
// See if the return type of the method is outside the class hierarchy
// 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, then
// cannot use a dispatcher because the target cannot be released.
if (exposeProxy || !isStatic) {
return INVOKE_TARGET;
}
Class<?> returnType = method.getReturnType();
if (returnType.isAssignableFrom(targetClass)) {
if (targetClass == returnType) {
if (logger.isDebugEnabled()) {
logger.debug("Method return type is assignable from target type and " +
"may therefore return 'this' - using INVOKE_TARGET: " + method);
logger.debug("Method " + method +
"has return type same as target type (may return this) - using INVOKE_TARGET");
}
return INVOKE_TARGET;
}
else {
else if (returnType.isPrimitive() || !returnType.isAssignableFrom(targetClass)) {
if (logger.isDebugEnabled()) {
logger.debug("Method return type ensures 'this' cannot be returned - " +
"using DISPATCH_TARGET: " + method);
logger.debug("Method " + method +
" has return type that ensures this cannot be returned- using DISPATCH_TARGET");
}
return DISPATCH_TARGET;
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Method " + method +
"has return type that is assignable from the target type (may return this) - " +
"using INVOKE_TARGET");
}
return INVOKE_TARGET;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -62,9 +62,9 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
@@ -98,7 +98,8 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
* Determine whether the Advisors contain matching introductions.
*/
private static boolean hasMatchingIntroductions(Advised config, Class<?> actualClass) {
for (Advisor advisor : config.getAdvisors()) {
for (int i = 0; i < config.getAdvisors().length; i++) {
Advisor advisor = config.getAdvisors()[i];
if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (ia.getClassFilter().matches(actualClass)) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@ public class ProxyCreatorSupport extends AdvisedSupport {
private AopProxyFactory aopProxyFactory;
private final List<AdvisedSupportListener> listeners = new LinkedList<AdvisedSupportListener>();
private List<AdvisedSupportListener> listeners = new LinkedList<AdvisedSupportListener>();
/** Set to true when the first AOP proxy has been created */
private boolean active = false;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -640,7 +640,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
}
public String getBeanName() {
return this.beanName;
return beanName;
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,8 +16,6 @@
package org.springframework.aop.framework;
import java.io.Closeable;
import org.springframework.beans.factory.Aware;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.DisposableBean;
@@ -50,9 +48,9 @@ public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanC
/**
* Set the ordering which will apply to this processor's implementation
* of {@link Ordered}, used when applying multiple processors.
* <p>The default value is {@code Ordered.LOWEST_PRECEDENCE}, meaning non-ordered.
* Set the ordering which will apply to this class's implementation
* of Ordered, used when applying multiple processors.
* <p>Default value is {@code Integer.MAX_VALUE}, meaning that it's non-ordered.
* @param order the ordering value
*/
public void setOrder(int order) {
@@ -129,7 +127,6 @@ public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanC
*/
protected boolean isConfigurationCallbackInterface(Class<?> ifc) {
return (InitializingBean.class == ifc || DisposableBean.class == ifc ||
Closeable.class == ifc || "java.lang.AutoCloseable".equals(ifc.getName()) ||
ObjectUtils.containsElement(ifc.getInterfaces(), Aware.class));
}
@@ -143,8 +140,7 @@ public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanC
*/
protected boolean isInternalLanguageInterface(Class<?> ifc) {
return (ifc.getName().equals("groovy.lang.GroovyObject") ||
ifc.getName().endsWith(".cglib.proxy.Factory") ||
ifc.getName().endsWith(".bytebuddy.MockAccess"));
ifc.getName().endsWith(".cglib.proxy.Factory"));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,15 +31,15 @@ import org.springframework.aop.Advisor;
public interface AdvisorAdapterRegistry {
/**
* Return an {@link Advisor} wrapping the given advice.
* Return an Advisor wrapping the given advice.
* <p>Should by default at least support
* {@link org.aopalliance.intercept.MethodInterceptor},
* {@link org.springframework.aop.MethodBeforeAdvice},
* {@link org.springframework.aop.AfterReturningAdvice},
* {@link org.springframework.aop.ThrowsAdvice}.
* @param advice object that should be an advice
* @return an Advisor wrapping the given advice (never {@code null};
* if the advice parameter is an Advisor, it is to be returned as-is)
* @return an Advisor wrapping the given advice. Never returns {@code null}.
* If the advice parameter is an Advisor, return it.
* @throws UnknownAdviceTypeException if no registered advisor adapter
* can wrap the supposed advice
*/
@@ -48,20 +48,21 @@ public interface AdvisorAdapterRegistry {
/**
* Return an array of AOP Alliance MethodInterceptors to allow use of the
* given Advisor in an interception-based framework.
* <p>Don't worry about the pointcut associated with the {@link Advisor}, if it is
* a {@link org.springframework.aop.PointcutAdvisor}: just return an interceptor.
* <p>Don't worry about the pointcut associated with the Advisor,
* if it's a PointcutAdvisor: just return an interceptor.
* @param advisor Advisor to find an interceptor for
* @return an array of MethodInterceptors to expose this Advisor's behavior
* @throws UnknownAdviceTypeException if the Advisor type is
* not understood by any registered AdvisorAdapter
* not understood by any registered AdvisorAdapter.
*/
MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException;
/**
* Register the given {@link AdvisorAdapter}. Note that it is not necessary to register
* Register the given AdvisorAdapter. Note that it is not necessary to register
* adapters for an AOP Alliance Interceptors or Spring Advices: these must be
* automatically recognized by an {@code AdvisorAdapterRegistry} implementation.
* @param adapter AdvisorAdapter that understands particular Advisor or Advice types
* automatically recognized by an AdvisorAdapterRegistry implementation.
* @param adapter AdvisorAdapter that understands a particular Advisor
* or Advice types
*/
void registerAdvisorAdapter(AdvisorAdapter adapter);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2012 the original author 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,13 +26,11 @@ import org.springframework.aop.AfterReturningAdvice;
import org.springframework.util.Assert;
/**
* Interceptor to wrap an {@link org.springframework.aop.AfterReturningAdvice}.
* Interceptor to wrap am {@link org.springframework.aop.AfterReturningAdvice}.
* Used internally by the AOP framework; application developers should not need
* to use this class directly.
*
* @author Rod Johnson
* @see MethodBeforeAdviceInterceptor
* @see ThrowsAdviceInterceptor
*/
@SuppressWarnings("serial")
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
@@ -49,7 +47,6 @@ public class AfterReturningAdviceInterceptor implements MethodInterceptor, After
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@ import java.io.Serializable;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.util.Assert;
@@ -31,13 +30,11 @@ import org.springframework.util.Assert;
* to use this class directly.
*
* @author Rod Johnson
* @see AfterReturningAdviceInterceptor
* @see ThrowsAdviceInterceptor
*/
@SuppressWarnings("serial")
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
private final MethodBeforeAdvice advice;
private MethodBeforeAdvice advice;
/**
@@ -49,10 +46,9 @@ public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeA
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,8 +50,6 @@ import org.springframework.util.Assert;
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see MethodBeforeAdviceInterceptor
* @see AfterReturningAdviceInterceptor
*/
public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
@@ -68,8 +66,9 @@ public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
/**
* Create a new ThrowsAdviceInterceptor for the given ThrowsAdvice.
* @param throwsAdvice the advice object that defines the exception handler methods
* (usually a {@link org.springframework.aop.ThrowsAdvice} implementation)
* @param throwsAdvice the advice object that defines the exception
* handler methods (usually a {@link org.springframework.aop.ThrowsAdvice}
* implementation)
*/
public ThrowsAdviceInterceptor(Object throwsAdvice) {
Assert.notNull(throwsAdvice, "Advice must not be null");
@@ -77,17 +76,14 @@ public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
Method[] methods = throwsAdvice.getClass().getMethods();
for (Method method : methods) {
if (method.getName().equals(AFTER_THROWING)) {
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length == 1 || paramTypes.length == 4) {
Class<?> throwableParam = paramTypes[paramTypes.length - 1];
if (Throwable.class.isAssignableFrom(throwableParam)) {
// An exception handler to register...
this.exceptionHandlerMap.put(throwableParam, method);
if (logger.isDebugEnabled()) {
logger.debug("Found exception handler method on throws advice: " + method);
}
}
if (method.getName().equals(AFTER_THROWING) &&
(method.getParameterTypes().length == 1 || method.getParameterTypes().length == 4) &&
Throwable.class.isAssignableFrom(method.getParameterTypes()[method.getParameterTypes().length - 1])
) {
// Have an exception handler
this.exceptionHandlerMap.put(method.getParameterTypes()[method.getParameterTypes().length - 1], method);
if (logger.isDebugEnabled()) {
logger.debug("Found exception handler method: " + method);
}
}
}
@@ -98,33 +94,14 @@ public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
}
}
/**
* Return the number of handler methods in this advice.
*/
public int getHandlerMethodCount() {
return this.exceptionHandlerMap.size();
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
Method handlerMethod = getExceptionHandler(ex);
if (handlerMethod != null) {
invokeHandlerMethod(mi, ex, handlerMethod);
}
throw ex;
}
}
/**
* Determine the exception handle method for the given exception.
* Determine the exception handle method. Can return null if not found.
* @param exception the exception thrown
* @return a handler for the given exception type, or {@code null} if none found
* @return a handler for the given exception type
*/
private Method getExceptionHandler(Throwable exception) {
Class<?> exceptionClass = exception.getClass();
@@ -142,10 +119,24 @@ public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
return handler;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
Method handlerMethod = getExceptionHandler(ex);
if (handlerMethod != null) {
invokeHandlerMethod(mi, ex, handlerMethod);
}
throw ex;
}
}
private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable {
Object[] handlerArgs;
if (method.getParameterTypes().length == 1) {
handlerArgs = new Object[] {ex};
handlerArgs = new Object[] { ex };
}
else {
handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex};
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,8 +54,7 @@ public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyC
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException(
"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
throw new IllegalStateException("Cannot use AdvisorAutoProxyCreator without a ConfigurableListableBeanFactory");
}
initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -55,25 +55,26 @@ import org.springframework.util.StringUtils;
* before invoking the bean itself.
*
* <p>This class distinguishes between "common" interceptors: shared for all proxies it
* creates, and "specific" interceptors: unique per bean instance. There need not be any
* common interceptors. If there are, they are set using the interceptorNames property.
* As with {@link org.springframework.aop.framework.ProxyFactoryBean}, interceptors names
* in the current factory are used rather than bean references to allow correct handling
* of prototype advisors and interceptors: for example, to support stateful mixins.
* Any advice type is supported for {@link #setInterceptorNames "interceptorNames"} entries.
* creates, and "specific" interceptors: unique per bean instance. There need not
* be any common interceptors. If there are, they are set using the interceptorNames
* property. As with ProxyFactoryBean, interceptors names in the current factory
* are used rather than bean references to allow correct handling of prototype
* advisors and interceptors: for example, to support stateful mixins.
* Any advice type is supported for "interceptorNames" entries.
*
* <p>Such auto-proxying is particularly useful if there's a large number of beans that
* need to be wrapped with similar proxies, i.e. delegating to the same interceptors.
* Instead of x repetitive proxy definitions for x target beans, you can register
* one single such post processor with the bean factory to achieve the same effect.
*
* <p>Subclasses can apply any strategy to decide if a bean is to be proxied, e.g. by type,
* by name, by definition details, etc. They can also return additional interceptors that
* should just be applied to the specific bean instance. A simple concrete implementation is
* {@link BeanNameAutoProxyCreator}, identifying the beans to be proxied via given names.
* <p>Subclasses can apply any strategy to decide if a bean is to be proxied,
* e.g. by type, by name, by definition details, etc. They can also return
* additional interceptors that should just be applied to the specific bean
* instance. The default concrete implementation is BeanNameAutoProxyCreator,
* identifying the beans to be proxied via a list of bean names.
*
* <p>Any number of {@link TargetSourceCreator} implementations can be used to create
* a custom target source: for example, to pool prototype objects. Auto-proxying will
* a custom target source - for example, to pool prototype objects. Auto-proxying will
* occur even if there is no advice, as long as a TargetSourceCreator specifies a custom
* {@link org.springframework.aop.TargetSource}. If there are no TargetSourceCreators set,
* or if none matches, a {@link org.springframework.aop.target.SingletonTargetSource}
@@ -155,8 +156,8 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
}
/**
* Specify the {@link AdvisorAdapterRegistry} to use.
* <p>Default is the global {@link AdvisorAdapterRegistry}.
* Specify the AdvisorAdapterRegistry to use.
* Default is the global AdvisorAdapterRegistry.
* @see org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry
*/
public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {
@@ -164,18 +165,18 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
}
/**
* Set custom {@code TargetSourceCreators} to be applied in this order.
* If the list is empty, or they all return null, a {@link SingletonTargetSource}
* Set custom TargetSourceCreators to be applied in this order.
* If the list is empty, or they all return null, a SingletonTargetSource
* will be created for each bean.
* <p>Note that TargetSourceCreators will kick in even for target beans
* where no advices or advisors have been found. If a {@code TargetSourceCreator}
* returns a {@link TargetSource} for a specific bean, that bean will be proxied
* where no advices or advisors have been found. If a TargetSourceCreator
* returns a TargetSource for a specific bean, that bean will be proxied
* in any case.
* <p>{@code TargetSourceCreators} can only be invoked if this post processor is used
* in a {@link BeanFactory} and its {@link BeanFactoryAware} callback is triggered.
* @param targetSourceCreators the list of {@code TargetSourceCreators}.
* Ordering is significant: The {@code TargetSource} returned from the first matching
* {@code TargetSourceCreator} (that is, the first that returns non-null) will be used.
* <p>TargetSourceCreators can only be invoked if this post processor is used
* in a BeanFactory, and its BeanFactoryAware callback is used.
* @param targetSourceCreators list of TargetSourceCreator.
* Ordering is significant: The TargetSource returned from the first matching
* TargetSourceCreator (that is, the first that returns non-null) will be used.
*/
public void setCustomTargetSourceCreators(TargetSourceCreator... targetSourceCreators) {
this.customTargetSourceCreators = targetSourceCreators;
@@ -206,8 +207,8 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
}
/**
* Return the owning {@link BeanFactory}.
* May be {@code null}, as this post-processor doesn't need to belong to a bean factory.
* Return the owning BeanFactory.
* May be {@code null}, as this object doesn't need to belong to a bean factory.
*/
protected BeanFactory getBeanFactory() {
return this.beanFactory;
@@ -412,7 +413,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
// Found a matching TargetSource.
if (logger.isDebugEnabled()) {
logger.debug("TargetSourceCreator [" + tsc +
"] found custom TargetSource for bean with name '" + beanName + "'");
" found custom TargetSource for bean with name '" + beanName + "'");
}
return ts;
}
@@ -454,7 +455,10 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
@@ -553,7 +557,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
* Subclasses may choose to implement this: for example,
* to change the interfaces exposed.
* <p>The default implementation is empty.
* @param proxyFactory a ProxyFactory that is already configured with
* @param proxyFactory ProxyFactory that is already configured with
* TargetSource and interfaces and will be used to create the proxy
* immediately after this method returns
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
package org.springframework.aop.framework.autoproxy;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.logging.Log;
@@ -43,7 +43,7 @@ public class BeanFactoryAdvisorRetrievalHelper {
private final ConfigurableListableBeanFactory beanFactory;
private volatile String[] cachedAdvisorBeanNames;
private String[] cachedAdvisorBeanNames;
/**
@@ -64,19 +64,22 @@ public class BeanFactoryAdvisorRetrievalHelper {
*/
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
String[] advisorNames = null;
synchronized (this) {
advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
}
if (advisorNames.length == 0) {
return new ArrayList<Advisor>();
return new LinkedList<Advisor>();
}
List<Advisor> advisors = new ArrayList<Advisor>();
List<Advisor> advisors = new LinkedList<Advisor>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2012 the original author 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,16 +19,15 @@ package org.springframework.aop.framework.autoproxy;
import org.springframework.beans.factory.BeanNameAware;
/**
* {@code BeanPostProcessor} implementation that creates AOP proxies based on all
* candidate {@code Advisor}s in the current {@code BeanFactory}. This class is
* completely generic; it contains no special code to handle any particular aspects,
* such as pooling aspects.
* BeanPostProcessor implementation that creates AOP proxies based on all candidate
* Advisors in the current BeanFactory. This class is completely generic; it contains
* no special code to handle any particular aspects, such as pooling aspects.
*
* <p>It's possible to filter out advisors - for example, to use multiple post processors
* of this type in the same factory - by setting the {@code usePrefix} property to true,
* in which case only advisors beginning with the DefaultAdvisorAutoProxyCreator's bean
* name followed by a dot (like "aapc.") will be used. This default prefix can be changed
* from the bean name by setting the {@code advisorBeanNamePrefix} property.
* of this type in the same factory - by setting the {@code usePrefix} property
* to true, in which case only advisors beginning with the DefaultAdvisorAutoProxyCreator's
* bean name followed by a dot (like "aapc.") will be used. This default prefix can be
* changed from the bean name by setting the {@code advisorBeanNamePrefix} property.
* The separator (.) will also be used in this case.
*
* @author Rod Johnson
@@ -41,22 +40,22 @@ public class DefaultAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCrea
public final static String SEPARATOR = ".";
private boolean usePrefix = false;
private boolean usePrefix;
private String advisorBeanNamePrefix;
/**
* Set whether to only include advisors with a certain prefix in the bean name.
* <p>Default is {@code false}, including all beans of type {@code Advisor}.
* @see #setAdvisorBeanNamePrefix
* Set whether to exclude advisors with a certain prefix
* in the bean name.
*/
public void setUsePrefix(boolean usePrefix) {
this.usePrefix = usePrefix;
}
/**
* Return whether to only include advisors with a certain prefix in the bean name.
* Return whether to exclude advisors with a certain prefix
* in the bean name.
*/
public boolean isUsePrefix() {
return this.usePrefix;
@@ -90,7 +89,7 @@ public class DefaultAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCrea
/**
* Consider {@code Advisor} beans with the specified prefix as eligible, if activated.
* Consider Advisor beans with the specified prefix as eligible, if activated.
* @see #setUsePrefix
* @see #setAdvisorBeanNamePrefix
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,12 +22,12 @@ import org.aopalliance.intercept.MethodInvocation;
/**
* Base class for monitoring interceptors, such as performance monitors.
* Provides configurable "prefix and "suffix" properties that help to
* classify/group performance monitoring results.
* Provides {@code prefix} and {@code suffix} properties
* that help to classify/group performance monitoring results.
*
* <p>In their {@link #invokeUnderTrace} implementation, subclasses should call the
* {@link #createInvocationTraceName} method to create a name for the given trace,
* including information about the method invocation along with a prefix/suffix.
* <p>Subclasses should call the {@code createInvocationTraceName(MethodInvocation)}
* method to create a name for the given trace that includes information about the
* method invocation under trace along with the prefix and suffix added as appropriate.
*
* @author Rob Harrop
* @author Juergen Hoeller
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -58,12 +58,6 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser
*/
private boolean hideProxyClassNames = false;
/**
* Indicates whether to pass an exception to the logger.
* @see #writeToLog(Log, String, Throwable)
*/
private boolean logExceptionStackTrace = true;
/**
* Set whether to use a dynamic logger or a static logger.
@@ -104,17 +98,6 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser
this.hideProxyClassNames = hideProxyClassNames;
}
/**
* Set whether to pass an exception to the logger, suggesting inclusion
* of its stack trace into the log. Default is "true"; set this to "false"
* in order to reduce the log output to just the trace message (which may
* include the exception class name and exception message, if applicable).
* @since 4.3.10
*/
public void setLogExceptionStackTrace(boolean logExceptionStackTrace) {
this.logExceptionStackTrace = logExceptionStackTrace;
}
/**
* Determines whether or not logging is enabled for the particular {@code MethodInvocation}.
@@ -188,40 +171,6 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser
return logger.isTraceEnabled();
}
/**
* Write the supplied trace message to the supplied {@code Log} instance.
* <p>To be called by {@link #invokeUnderTrace} for enter/exit messages.
* <p>Delegates to {@link #writeToLog(Log, String, Throwable)} as the
* ultimate delegate that controls the underlying logger invocation.
* @since 4.3.10
* @see #writeToLog(Log, String, Throwable)
*/
protected void writeToLog(Log logger, String message) {
writeToLog(logger, message, null);
}
/**
* Write the supplied trace message and {@link Throwable} to the
* supplied {@code Log} instance.
* <p>To be called by {@link #invokeUnderTrace} for enter/exit outcomes,
* potentially including an exception. Note that an exception's stack trace
* won't get logged when {@link #setLogExceptionStackTrace} is "false".
* <p>By default messages are written at {@code TRACE} level. Subclasses
* can override this method to control which level the message is written
* at, typically also overriding {@link #isLogEnabled} accordingly.
* @since 4.3.10
* @see #setLogExceptionStackTrace
* @see #isLogEnabled
*/
protected void writeToLog(Log logger, String message, Throwable ex) {
if (ex != null && this.logExceptionStackTrace) {
logger.trace(message, ex);
}
else {
logger.trace(message);
}
}
/**
* Subclasses must override this method to perform any tracing around the
@@ -231,15 +180,13 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser
* <p>By default, the passed-in {@code Log} instance will have log level
* "trace" enabled. Subclasses do not have to check for this again, unless
* they overwrite the {@code isInterceptorEnabled} method to modify
* the default behavior, and may delegate to {@code writeToLog} for actual
* messages to be written.
* the default behavior.
* @param logger the {@code Log} to write trace messages to
* @return the result of the call to {@code MethodInvocation.proceed()}
* @throws Throwable if the call to {@code MethodInvocation.proceed()}
* encountered any errors
* @see #isInterceptorEnabled
* @see #isLogEnabled
* @see #writeToLog(Log, String)
* @see #writeToLog(Log, String, Throwable)
*/
protected abstract Object invokeUnderTrace(MethodInvocation invocation, Log logger) throws Throwable;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -228,7 +228,6 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
return beanFactory.getBean(TaskExecutor.class);
}
catch (NoUniqueBeanDefinitionException ex) {
logger.debug("Could not find unique TaskExecutor bean", ex);
try {
return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);
}
@@ -242,14 +241,8 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
}
catch (NoSuchBeanDefinitionException ex) {
logger.debug("Could not find default TaskExecutor bean", ex);
try {
return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);
}
catch (NoSuchBeanDefinitionException ex2) {
logger.info("No task executor bean found for async processing: " +
"no bean of type TaskExecutor and no bean named 'taskExecutor' either");
}
// Giving up -> either using local default executor or none at all...
logger.info("No TaskExecutor bean found for async processing");
}
}
return null;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -128,20 +128,20 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
/**
* The default message used for writing method entry messages.
*/
private static final String DEFAULT_ENTER_MESSAGE = "Entering method '" +
PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
private static final String DEFAULT_ENTER_MESSAGE =
"Entering method '" + PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
/**
* The default message used for writing method exit messages.
*/
private static final String DEFAULT_EXIT_MESSAGE = "Exiting method '" +
PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
private static final String DEFAULT_EXIT_MESSAGE =
"Exiting method '" + PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
/**
* The default message used for writing exception messages.
*/
private static final String DEFAULT_EXCEPTION_MESSAGE = "Exception thrown in method '" +
PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
private static final String DEFAULT_EXCEPTION_MESSAGE =
"Exception thrown in method '" + PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
/**
* The {@code Pattern} used to match placeholders.
@@ -182,14 +182,14 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
* </ul>
*/
public void setEnterMessage(String enterMessage) throws IllegalArgumentException {
Assert.hasText(enterMessage, "enterMessage must not be empty");
Assert.hasText(enterMessage, "'enterMessage' must not be empty");
checkForInvalidPlaceholders(enterMessage);
Assert.doesNotContain(enterMessage, PLACEHOLDER_RETURN_VALUE,
"enterMessage cannot contain placeholder " + PLACEHOLDER_RETURN_VALUE);
"enterMessage cannot contain placeholder [" + PLACEHOLDER_RETURN_VALUE + "]");
Assert.doesNotContain(enterMessage, PLACEHOLDER_EXCEPTION,
"enterMessage cannot contain placeholder " + PLACEHOLDER_EXCEPTION);
"enterMessage cannot contain placeholder [" + PLACEHOLDER_EXCEPTION + "]");
Assert.doesNotContain(enterMessage, PLACEHOLDER_INVOCATION_TIME,
"enterMessage cannot contain placeholder " + PLACEHOLDER_INVOCATION_TIME);
"enterMessage cannot contain placeholder [" + PLACEHOLDER_INVOCATION_TIME + "]");
this.enterMessage = enterMessage;
}
@@ -206,10 +206,10 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
* </ul>
*/
public void setExitMessage(String exitMessage) {
Assert.hasText(exitMessage, "exitMessage must not be empty");
Assert.hasText(exitMessage, "'exitMessage' must not be empty");
checkForInvalidPlaceholders(exitMessage);
Assert.doesNotContain(exitMessage, PLACEHOLDER_EXCEPTION,
"exitMessage cannot contain placeholder" + PLACEHOLDER_EXCEPTION);
"exitMessage cannot contain placeholder [" + PLACEHOLDER_EXCEPTION + "]");
this.exitMessage = exitMessage;
}
@@ -225,10 +225,12 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
* </ul>
*/
public void setExceptionMessage(String exceptionMessage) {
Assert.hasText(exceptionMessage, "exceptionMessage must not be empty");
Assert.hasText(exceptionMessage, "'exceptionMessage' must not be empty");
checkForInvalidPlaceholders(exceptionMessage);
Assert.doesNotContain(exceptionMessage, PLACEHOLDER_RETURN_VALUE,
"exceptionMessage cannot contain placeholder " + PLACEHOLDER_RETURN_VALUE);
"exceptionMessage cannot contain placeholder [" + PLACEHOLDER_RETURN_VALUE + "]");
Assert.doesNotContain(exceptionMessage, PLACEHOLDER_INVOCATION_TIME,
"exceptionMessage cannot contain placeholder [" + PLACEHOLDER_INVOCATION_TIME + "]");
this.exceptionMessage = exceptionMessage;
}
@@ -260,8 +262,8 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
stopWatch.stop();
}
exitThroughException = true;
writeToLog(logger, replacePlaceholders(
this.exceptionMessage, invocation, null, ex, stopWatch.getTotalTimeMillis()), ex);
writeToLog(logger,
replacePlaceholders(this.exceptionMessage, invocation, null, ex, stopWatch.getTotalTimeMillis()), ex);
throw ex;
}
finally {
@@ -269,12 +271,35 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
if (stopWatch.isRunning()) {
stopWatch.stop();
}
writeToLog(logger, replacePlaceholders(
this.exitMessage, invocation, returnValue, null, stopWatch.getTotalTimeMillis()));
writeToLog(logger,
replacePlaceholders(this.exitMessage, invocation, returnValue, null, stopWatch.getTotalTimeMillis()));
}
}
}
/**
* Writes the supplied message to the supplied {@code Log} instance.
* @see #writeToLog(org.apache.commons.logging.Log, String, Throwable)
*/
protected void writeToLog(Log logger, String message) {
writeToLog(logger, message, null);
}
/**
* Writes the supplied message and {@link Throwable} to the
* supplied {@code Log} instance. By default messages are written
* at {@code TRACE} level. Sub-classes can override this method
* to control which level the message is written at.
*/
protected void writeToLog(Log logger, String message, Throwable ex) {
if (ex != null) {
logger.trace(message, ex);
}
else {
logger.trace(message);
}
}
/**
* Replace the placeholders in the given message with the supplied values,
* or values derived from those supplied.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 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.
@@ -121,7 +121,7 @@ public class JamonPerformanceMonitorInterceptor extends AbstractMonitoringInterc
finally {
monitor.stop();
if (!this.trackAllInvocations || isLogEnabled(logger)) {
writeToLog(logger, "JAMon performance statistics for method [" + name + "]:\n" + monitor);
logger.trace("JAMon performance statistics for method [" + name + "]:\n" + monitor);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -63,7 +63,7 @@ public class PerformanceMonitorInterceptor extends AbstractMonitoringInterceptor
}
finally {
stopWatch.stop();
writeToLog(logger, stopWatch.shortSummary());
logger.trace(stopWatch.shortSummary());
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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,13 +29,13 @@ import org.apache.commons.logging.LogFactory;
*/
public class SimpleAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
private static final Log logger = LogFactory.getLog(SimpleAsyncUncaughtExceptionHandler.class);
private final Log logger = LogFactory.getLog(SimpleAsyncUncaughtExceptionHandler.class);
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
if (logger.isErrorEnabled()) {
logger.error("Unexpected error occurred invoking async method: " + method, ex);
logger.error(String.format("Unexpected error occurred invoking async " +
"method '%s'.", method), ex);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -55,14 +55,14 @@ public class SimpleTraceInterceptor extends AbstractTraceInterceptor {
@Override
protected Object invokeUnderTrace(MethodInvocation invocation, Log logger) throws Throwable {
String invocationDescription = getInvocationDescription(invocation);
writeToLog(logger, "Entering " + invocationDescription);
logger.trace("Entering " + invocationDescription);
try {
Object rval = invocation.proceed();
writeToLog(logger, "Exiting " + invocationDescription);
logger.trace("Exiting " + invocationDescription);
return rval;
}
catch (Throwable ex) {
writeToLog(logger, "Exception thrown in " + invocationDescription, ex);
logger.trace("Exception thrown in " + invocationDescription, ex);
throw ex;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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,8 +50,7 @@ import org.springframework.util.ClassUtils;
* @see #setProxyTargetClass
*/
@SuppressWarnings("serial")
public class ScopedProxyFactoryBean extends ProxyConfig
implements FactoryBean<Object>, BeanFactoryAware, AopInfrastructureBean {
public class ScopedProxyFactoryBean extends ProxyConfig implements FactoryBean<Object>, BeanFactoryAware {
/** The TargetSource that manages scoping */
private final SimpleBeanTargetSource scopedTargetSource = new SimpleBeanTargetSource();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 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,7 @@ public abstract class ScopedProxyUtils {
}
/**
* Generate the bean name that is used within the scoped proxy to reference the target bean.
* Generates the bean name that is used within the scoped proxy to reference the target bean.
* @param originalBeanName the original name of bean
* @return the generated bean to be used to reference the target bean
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -130,9 +130,8 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
*/
@Override
public boolean matches(Method method, Class<?> targetClass) {
return ((targetClass != null && targetClass != method.getDeclaringClass() &&
matchesPattern(ClassUtils.getQualifiedMethodName(method, targetClass))) ||
matchesPattern(ClassUtils.getQualifiedMethodName(method, method.getDeclaringClass())));
return ((targetClass != null && matchesPattern(ClassUtils.getQualifiedMethodName(method, targetClass))) ||
matchesPattern(ClassUtils.getQualifiedMethodName(method)));
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Convenient class for building up pointcuts. All methods return
@@ -187,14 +188,21 @@ public class ComposablePointcut implements Pointcut, Serializable {
if (!(other instanceof ComposablePointcut)) {
return false;
}
ComposablePointcut otherPointcut = (ComposablePointcut) other;
return (this.classFilter.equals(otherPointcut.classFilter) &&
this.methodMatcher.equals(otherPointcut.methodMatcher));
ComposablePointcut that = (ComposablePointcut) other;
return ObjectUtils.nullSafeEquals(that.classFilter, this.classFilter) &&
ObjectUtils.nullSafeEquals(that.methodMatcher, this.methodMatcher);
}
@Override
public int hashCode() {
return this.classFilter.hashCode() * 37 + this.methodMatcher.hashCode();
int code = 17;
if (this.classFilter != null) {
code = 37 * code + this.classFilter.hashCode();
}
if (this.methodMatcher != null) {
code = 37 * code + this.methodMatcher.hashCode();
}
return code;
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,8 @@ import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.core.ControlFlow;
import org.springframework.core.ControlFlowFactory;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -32,7 +34,7 @@ import org.springframework.util.ObjectUtils;
*
* @author Rod Johnson
* @author Rob Harrop
* @author Juergen Hoeller
* @see org.springframework.core.ControlFlow
*/
@SuppressWarnings("serial")
public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable {
@@ -41,7 +43,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
private String methodName;
private volatile int evaluations;
private int evaluations;
/**
@@ -53,11 +55,11 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
}
/**
* Construct a new pointcut that matches all calls below the given method
* in the given class. If no method name is given, matches all control flows
* below the given class.
* Construct a new pointcut that matches all calls below the
* given method in the given class. If the method name is null,
* matches all control flows below that class.
* @param clazz the clazz
* @param methodName the name of the method (may be {@code null})
* @param methodName the name of the method
*/
public ControlFlowPointcut(Class<?> clazz, String methodName) {
Assert.notNull(clazz, "Class must not be null");
@@ -91,14 +93,8 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
this.evaluations++;
for (StackTraceElement element : new Throwable().getStackTrace()) {
if (element.getClassName().equals(this.clazz.getName()) &&
(this.methodName == null || element.getMethodName().equals(this.methodName))) {
return true;
}
}
return false;
ControlFlow cflow = ControlFlowFactory.createControlFlow();
return (this.methodName != null ? cflow.under(this.clazz, this.methodName) : cflow.under(this.clazz));
}
/**
@@ -134,7 +130,8 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
@Override
public int hashCode() {
int code = this.clazz.hashCode();
int code = 17;
code = 37 * code + this.clazz.hashCode();
if (this.methodName != null) {
code = 37 * code + this.methodName.hashCode();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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 DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil
private final Set<Class<?>> interfaces = new LinkedHashSet<Class<?>>();
private int order = Ordered.LOWEST_PRECEDENCE;
private int order = Integer.MAX_VALUE;
/**
@@ -104,7 +104,7 @@ public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil
@Override
public Class<?>[] getInterfaces() {
return ClassUtils.toClassArray(this.interfaces);
return this.interfaces.toArray(new Class<?>[this.interfaces.size()]);
}
@Override
@@ -118,6 +118,7 @@ public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil
}
}
public void setOrder(int order) {
this.order = order;
}
@@ -127,6 +128,7 @@ public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil
return this.order;
}
@Override
public Advice getAdvice() {
return this.advice;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,8 +23,6 @@ import org.springframework.aop.MethodMatcher;
/**
* Convenient abstract superclass for dynamic method matchers,
* which do care about arguments at runtime.
*
* @author Rod Johnson
*/
public abstract class DynamicMethodMatcher implements MethodMatcher {
@@ -24,7 +24,7 @@ import org.springframework.aop.Pointcut;
* Convenient superclass when we want to force subclasses to
* implement MethodMatcher interface, but subclasses
* will want to be pointcuts. The getClassFilter() method can
* be overridden to customize ClassFilter behaviour as well.
* be overriden to customize ClassFilter behaviour as well.
*
* @author Rod Johnson
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -53,15 +53,15 @@ public class IntroductionInfoSupport implements IntroductionInfo, Serializable {
* due to the delegate implementing it. Call this method to exclude
* internal interfaces from being visible at the proxy level.
* <p>Does nothing if the interface is not implemented by the delegate.
* @param ifc the interface to suppress
* @param intf the interface to suppress
*/
public void suppressInterface(Class<?> ifc) {
this.publishedInterfaces.remove(ifc);
public void suppressInterface(Class<?> intf) {
this.publishedInterfaces.remove(intf);
}
@Override
public Class<?>[] getInterfaces() {
return ClassUtils.toClassArray(this.publishedInterfaces);
return this.publishedInterfaces.toArray(new Class<?>[this.publishedInterfaces.size()]);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 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,7 +27,7 @@ import org.springframework.util.PatternMatchUtils;
/**
* Pointcut bean for simple method name matches, as alternative to regexp patterns.
* Does not handle overloaded methods: all methods with a given name will be eligible.
* Does not handle overloaded methods: all methods *with a given name will be eligible.
*
* @author Juergen Hoeller
* @author Rod Johnson
@@ -94,7 +94,7 @@ public abstract class Pointcuts {
@SuppressWarnings("serial")
private static class SetterPointcut extends StaticMethodMatcherPointcut implements Serializable {
public static final SetterPointcut INSTANCE = new SetterPointcut();
public static SetterPointcut INSTANCE = new SetterPointcut();
@Override
public boolean matches(Method method, Class<?> targetClass) {
@@ -115,7 +115,7 @@ public abstract class Pointcuts {
@SuppressWarnings("serial")
private static class GetterPointcut extends StaticMethodMatcherPointcut implements Serializable {
public static final GetterPointcut INSTANCE = new GetterPointcut();
public static GetterPointcut INSTANCE = new GetterPointcut();
@Override
public boolean matches(Method method, Class<?> targetClass) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2012 the original author 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,8 +21,7 @@ import java.io.Serializable;
import org.springframework.aop.ClassFilter;
/**
* Simple ClassFilter implementation that passes classes (and optionally subclasses).
*
* Simple ClassFilter implementation that passes classes (and optionally subclasses)
* @author Rod Johnson
*/
@SuppressWarnings("serial")
@@ -38,7 +37,7 @@ public class RootClassFilter implements ClassFilter, Serializable {
@Override
public boolean matches(Class<?> candidate) {
return this.clazz.isAssignableFrom(candidate);
return clazz.isAssignableFrom(candidate);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,8 +23,6 @@ import org.springframework.aop.MethodMatcher;
/**
* Convenient abstract superclass for static method matchers, which don't care
* about arguments at runtime.
*
* @author Rod Johnson
*/
public abstract class StaticMethodMatcher implements MethodMatcher {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,10 +36,10 @@ import org.springframework.util.Assert;
public abstract class StaticMethodMatcherPointcutAdvisor extends StaticMethodMatcherPointcut
implements PointcutAdvisor, Ordered, Serializable {
private Advice advice;
private int order = Integer.MAX_VALUE;
private Advice advice;
/**
* Create a new StaticMethodMatcherPointcutAdvisor,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Simple Pointcut that looks for a specific Java 5 annotation
@@ -45,15 +46,16 @@ public class AnnotationMatchingPointcut implements Pointcut {
* @param classAnnotationType the annotation type to look for at the class level
*/
public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationType) {
this(classAnnotationType, false);
this.classFilter = new AnnotationClassFilter(classAnnotationType);
this.methodMatcher = MethodMatcher.TRUE;
}
/**
* Create a new AnnotationMatchingPointcut for the given annotation type.
* @param classAnnotationType the annotation type to look for at the class level
* @param checkInherited whether to also check the superclasses and interfaces
* as well as meta-annotations for the annotation type
* @see AnnotationClassFilter#AnnotationClassFilter(Class, boolean)
* @param checkInherited whether to explicitly check the superclasses and
* interfaces for the annotation type as well (even if the annotation type
* is not marked as inherited itself)
*/
public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationType, boolean checkInherited) {
this.classFilter = new AnnotationClassFilter(classAnnotationType, checkInherited);
@@ -107,14 +109,21 @@ public class AnnotationMatchingPointcut implements Pointcut {
if (!(other instanceof AnnotationMatchingPointcut)) {
return false;
}
AnnotationMatchingPointcut otherPointcut = (AnnotationMatchingPointcut) other;
return (this.classFilter.equals(otherPointcut.classFilter) &&
this.methodMatcher.equals(otherPointcut.methodMatcher));
AnnotationMatchingPointcut that = (AnnotationMatchingPointcut) other;
return ObjectUtils.nullSafeEquals(that.classFilter, this.classFilter) &&
ObjectUtils.nullSafeEquals(that.methodMatcher, this.methodMatcher);
}
@Override
public int hashCode() {
return this.classFilter.hashCode() * 37 + this.methodMatcher.hashCode();
int code = 17;
if (this.classFilter != null) {
code = 37 * code + this.classFilter.hashCode();
}
if (this.methodMatcher != null) {
code = 37 * code + this.methodMatcher.hashCode();
}
return code;
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -60,7 +60,7 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
private String targetBeanName;
/** Class of the target */
private volatile Class<?> targetClass;
private Class<?> targetClass;
/**
* BeanFactory that owns this TargetSource. We need to hold onto this
@@ -120,28 +120,21 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
@Override
public Class<?> getTargetClass() {
Class<?> targetClass = this.targetClass;
if (targetClass != null) {
return targetClass;
}
synchronized (this) {
// Full check within synchronization, entering the BeanFactory interaction algorithm only once...
targetClass = this.targetClass;
if (targetClass == null && this.beanFactory != null) {
// Determine type of the target bean.
targetClass = this.beanFactory.getType(this.targetBeanName);
if (targetClass == null) {
if (logger.isTraceEnabled()) {
logger.trace("Getting bean with name '" + this.targetBeanName + "' for type determination");
}
Object beanInstance = this.beanFactory.getBean(this.targetBeanName);
targetClass = beanInstance.getClass();
public synchronized Class<?> getTargetClass() {
if (this.targetClass == null && this.beanFactory != null) {
// Determine type of the target bean.
this.targetClass = this.beanFactory.getType(this.targetBeanName);
if (this.targetClass == null) {
if (logger.isTraceEnabled()) {
logger.trace("Getting bean with name '" + this.targetBeanName + "' in order to determine type");
}
Object beanInstance = this.beanFactory.getBean(this.targetBeanName);
if (beanInstance != null) {
this.targetClass = beanInstance.getClass();
}
this.targetClass = targetClass;
}
return targetClass;
}
return this.targetClass;
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -74,8 +74,8 @@ public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFac
* @param target the bean instance to destroy
*/
protected void destroyPrototypeInstance(Object target) {
if (logger.isDebugEnabled()) {
logger.debug("Destroying instance of bean '" + getTargetBeanName() + "'");
if (this.logger.isDebugEnabled()) {
this.logger.debug("Destroying instance of bean '" + getTargetBeanName() + "'");
}
if (getBeanFactory() instanceof ConfigurableBeanFactory) {
((ConfigurableBeanFactory) getBeanFactory()).destroyBean(getTargetBeanName(), target);
@@ -44,7 +44,7 @@ import static org.junit.Assert.*;
* @author Ramnivas Laddad
* @since 2.0
*/
public class MethodInvocationProceedingJoinPointTests {
public final class MethodInvocationProceedingJoinPointTests {
@Test
public void testingBindingWithJoinPoint() {
@@ -217,7 +217,7 @@ public class MethodInvocationProceedingJoinPointTests {
itb.unreliableFileOperation();
}
catch (IOException ex) {
// we don't really care...
// we don't realy care...
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,26 +37,26 @@ import static org.junit.Assert.*;
* @author Juergen Hoeller
* @author Chris Beams
*/
public class ArgumentBindingTests {
public final class ArgumentBindingTests {
@Test(expected = IllegalArgumentException.class)
@Test(expected=IllegalArgumentException.class)
public void testBindingInPointcutUsedByAdvice() {
TestBean tb = new TestBean();
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
proxyFactory.addAspect(NamedPointcutWithArgs.class);
ITestBean proxiedTestBean = proxyFactory.getProxy();
proxiedTestBean.setName("Supercalifragalisticexpialidocious");
ITestBean proxiedTestBean = (ITestBean) proxyFactory.getProxy();
proxiedTestBean.setName("Supercalifragalisticexpialidocious"); // should throw
}
@Test(expected = IllegalStateException.class)
@Test(expected=IllegalStateException.class)
public void testAnnotationArgumentNameBinding() {
TransactionalBean tb = new TransactionalBean();
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
proxyFactory.addAspect(PointcutWithAnnotationArgument.class);
ITransactionalBean proxiedTestBean = proxyFactory.getProxy();
proxiedTestBean.doInTransaction();
ITransactionalBean proxiedTestBean = (ITransactionalBean) proxyFactory.getProxy();
proxiedTestBean.doInTransaction(); // should throw
}
@Test
@@ -71,7 +71,6 @@ public class ArgumentBindingTests {
assertEquals("formal", pnames[0]);
}
public void methodWithOneParam(String aParam) {
}
@@ -101,6 +100,9 @@ public class ArgumentBindingTests {
}
/**
* @author Juergen Hoeller
*/
@Aspect
class PointcutWithAnnotationArgument {
@@ -113,6 +115,9 @@ class PointcutWithAnnotationArgument {
}
/**
* @author Adrian Colyer
*/
@Aspect
class NamedPointcutWithArgs {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,7 +47,7 @@ public final class ConcurrencyThrottleInterceptorTests {
public void testSerializable() throws Exception {
DerivedTestBean tb = new DerivedTestBean();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(ITestBean.class);
proxyFactory.setInterfaces(new Class[] {ITestBean.class});
ConcurrencyThrottleInterceptor cti = new ConcurrencyThrottleInterceptor();
proxyFactory.addAdvice(cti);
proxyFactory.setTarget(tb);
@@ -75,7 +75,7 @@ public final class ConcurrencyThrottleInterceptorTests {
private void testMultipleThreads(int concurrencyLimit) {
TestBean tb = new TestBean();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(ITestBean.class);
proxyFactory.setInterfaces(new Class[] {ITestBean.class});
ConcurrencyThrottleInterceptor cti = new ConcurrencyThrottleInterceptor();
cti.setConcurrencyLimit(concurrencyLimit);
proxyFactory.addAdvice(cti);
@@ -95,7 +95,7 @@ public final class ConcurrencyThrottleInterceptorTests {
ex.printStackTrace();
}
threads[i] = new ConcurrencyThread(proxy,
i % 2 == 0 ? new OutOfMemoryError() : new IllegalStateException());
i % 2 == 0 ? (Throwable) new OutOfMemoryError() : (Throwable) new IllegalStateException());
threads[i].start();
}
for (int i = 0; i < NR_OF_THREADS; i++) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -83,7 +83,7 @@ public final class CustomizableTraceInterceptorTests {
public void testSunnyDayPathLogsCorrectly() throws Throwable {
MethodInvocation methodInvocation = mock(MethodInvocation.class);
given(methodInvocation.getMethod()).willReturn(String.class.getMethod("toString"));
given(methodInvocation.getMethod()).willReturn(String.class.getMethod("toString", new Class[]{}));
given(methodInvocation.getThis()).willReturn(this);
Log log = mock(Log.class);
@@ -101,7 +101,7 @@ public final class CustomizableTraceInterceptorTests {
MethodInvocation methodInvocation = mock(MethodInvocation.class);
IllegalArgumentException exception = new IllegalArgumentException();
given(methodInvocation.getMethod()).willReturn(String.class.getMethod("toString"));
given(methodInvocation.getMethod()).willReturn(String.class.getMethod("toString", new Class[]{}));
given(methodInvocation.getThis()).willReturn(this);
given(methodInvocation.proceed()).willThrow(exception);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@ public final class SimpleTraceInterceptorTests {
@Test
public void testSunnyDayPathLogsCorrectly() throws Throwable {
MethodInvocation mi = mock(MethodInvocation.class);
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
given(mi.getMethod()).willReturn(String.class.getMethod("toString", new Class[]{}));
given(mi.getThis()).willReturn(this);
Log log = mock(Log.class);
@@ -48,7 +48,7 @@ public final class SimpleTraceInterceptorTests {
@Test
public void testExceptionPathStillLogsCorrectly() throws Throwable {
MethodInvocation mi = mock(MethodInvocation.class);
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
given(mi.getMethod()).willReturn(String.class.getMethod("toString", new Class[]{}));
given(mi.getThis()).willReturn(this);
IllegalArgumentException exception = new IllegalArgumentException();
given(mi.proceed()).willThrow(exception);
@@ -29,15 +29,15 @@ import static org.springframework.tests.TestResourceUtils.*;
/**
* @author Mark Fisher
* @author Juergen Hoeller
* @author Chris Beams
* @author Juergen Hoeller
*/
public class ScopedProxyAutowireTests {
private static final Resource SCOPED_AUTOWIRE_FALSE_CONTEXT =
qualifiedResource(ScopedProxyAutowireTests.class, "scopedAutowireFalse.xml");
private static final Resource SCOPED_AUTOWIRE_TRUE_CONTEXT =
qualifiedResource(ScopedProxyAutowireTests.class, "scopedAutowireTrue.xml");
private static final Class<?> CLASS = ScopedProxyAutowireTests.class;
private static final Resource SCOPED_AUTOWIRE_TRUE_CONTEXT = qualifiedResource(CLASS, "scopedAutowireTrue.xml");
private static final Resource SCOPED_AUTOWIRE_FALSE_CONTEXT = qualifiedResource(CLASS, "scopedAutowireFalse.xml");
@Test
@@ -45,8 +45,6 @@ public class ScopedProxyAutowireTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(SCOPED_AUTOWIRE_FALSE_CONTEXT);
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, false, false)).contains("scoped"));
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, true, false)).contains("scoped"));
assertFalse(bf.containsSingleton("scoped"));
TestBean autowired = (TestBean) bf.getBean("autowired");
TestBean unscoped = (TestBean) bf.getBean("unscoped");
assertSame(unscoped, autowired.getChild());
@@ -56,9 +54,7 @@ public class ScopedProxyAutowireTests {
public void testScopedProxyReplacesAutowireCandidateTrue() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(SCOPED_AUTOWIRE_TRUE_CONTEXT);
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, true, false)).contains("scoped"));
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, false, false)).contains("scoped"));
assertFalse(bf.containsSingleton("scoped"));
TestBean autowired = (TestBean) bf.getBean("autowired");
TestBean scoped = (TestBean) bf.getBean("scoped");
assertSame(scoped, autowired.getChild());
@@ -1,6 +1,6 @@
<config xmlns="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<pointcut id="testPointcut" expression="execution(* foo(..)) and within(springbank.dao.AccountDao+)"/>
<pointcut id="testPointcut1" expression="execution(* springbank.dao.AccountDao.foo(..))"/>
@@ -9,4 +9,4 @@
<after method="foo" pointcut-ref="testPointcut"/>
</aspect>
</config>
</config>
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" scope="prototype" autowire-candidate="false">
<aop:scoped-proxy/>
</bean>
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="false">
<aop:scoped-proxy/>
</bean>
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="true"/>
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="true"/>
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
</beans>
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" scope="singleton" autowire-candidate="true">
<aop:scoped-proxy/>
</bean>
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="true">
<aop:scoped-proxy/>
</bean>
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="false"/>
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="false"/>
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
</beans>
+14 -1
View File
@@ -1,4 +1,5 @@
// Redefine the compileJava and compileTestJava tasks in order to compile sources with ajc instead of javac
// redefine the compileJava and compileTestJava tasks in order to
// compile sources with ajc instead of javac
configurations {
rt
@@ -7,14 +8,22 @@ configurations {
ajInpath
}
// exclude spring-aspects as a module within IDEA until IDEA-64446 is resolved
tasks.getByName("idea").onlyIf { false }
tasks.getByName("ideaModule").onlyIf { false }
compileJava {
actions = []
dependsOn configurations.ajc.getTaskDependencyFromProjectDependency(true, "compileJava")
def outputDir = project.sourceSets.main.output.classesDir
inputs.files(project.sourceSets.main.allSource + project.sourceSets.main.compileClasspath)
outputs.dir outputDir
ext.sourceCompatibility = project(":spring-core").compileJava.sourceCompatibility
ext.targetCompatibility = project(":spring-core").compileJava.targetCompatibility
doLast{
// Assemble runtime classpath from folders and JARs that actually exist
def runtimeClasspath = project.files(sourceSets.main.runtimeClasspath.files.findAll({ it.exists() }))
@@ -44,9 +53,13 @@ compileTestJava {
dependsOn jar
def outputDir = project.sourceSets.test.output.classesDir
inputs.files(project.sourceSets.test.allSource + project.sourceSets.test.compileClasspath)
outputs.dir outputDir
ext.sourceCompatibility = project(":spring-core").compileTestJava.sourceCompatibility
ext.targetCompatibility = project(":spring-core").compileTestJava.targetCompatibility
doLast{
// Assemble runtime classpath from folders and JARs that actually exist
def runtimeClasspath = project.files(sourceSets.test.runtimeClasspath.files.findAll({ it.exists() }))
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +34,6 @@ import org.springframework.context.annotation.Role;
* @see org.springframework.cache.annotation.CachingConfigurationSelector
*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class AspectJCachingConfiguration extends AbstractCachingConfiguration {
@Bean(name = CacheManagementConfigUtils.CACHE_ASPECT_BEAN_NAME)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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,7 +34,6 @@ import org.springframework.context.annotation.Role;
* @see org.springframework.cache.annotation.CachingConfigurationSelector
*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class AspectJJCacheConfiguration extends AbstractJCacheConfiguration {
@Bean(name = CacheManagementConfigUtils.JCACHE_ASPECT_BEAN_NAME)
@@ -45,7 +45,7 @@ import org.springframework.transaction.annotation.AnnotationTransactionAttribute
* @see javax.transaction.Transactional
* @see AnnotationTransactionAspect
*/
@RequiredTypes("javax.transaction.Transactional")
@RequiredTypes({"javax.transaction.Transactional"})
public aspect JtaAnnotationTransactionAspect extends AbstractTransactionAspect {
public JtaAnnotationTransactionAspect() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,45 +18,55 @@ package org.springframework.transaction.aspectj;
import java.lang.reflect.Method;
import org.junit.Before;
import org.junit.Test;
import org.springframework.tests.transaction.CallCountingTransactionManager;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.interceptor.TransactionAttribute;
import static org.junit.Assert.*;
/**
* @author Rod Johnson
* @author Ramnivas Laddad
* @author Juergen Hoeller
* @author Sam Brannen
*/
public class TransactionAspectTests {
@SuppressWarnings("deprecation")
public class TransactionAspectTests extends org.springframework.test.AbstractDependencyInjectionSpringContextTests {
private final CallCountingTransactionManager txManager = new CallCountingTransactionManager();
private CallCountingTransactionManager txManager;
private final TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface =
new TransactionalAnnotationOnlyOnClassWithNoInterface();
private TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface;
private final ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod =
new ClassWithProtectedAnnotatedMember();
private ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod;
private final ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod =
new ClassWithPrivateAnnotatedMember();
private ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod;
private final MethodAnnotationOnClassWithNoInterface methodAnnotationOnly =
new MethodAnnotationOnClassWithNoInterface();
private MethodAnnotationOnClassWithNoInterface methodAnnotationOnly = new MethodAnnotationOnClassWithNoInterface();
@Before
public void initContext() {
AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager);
public void setAnnotationOnlyOnClassWithNoInterface(
TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface) {
this.annotationOnlyOnClassWithNoInterface = annotationOnlyOnClassWithNoInterface;
}
public void setClassWithAnnotatedProtectedMethod(ClassWithProtectedAnnotatedMember aBean) {
this.beanWithAnnotatedProtectedMethod = aBean;
}
public void setClassWithAnnotatedPrivateMethod(ClassWithPrivateAnnotatedMember aBean) {
this.beanWithAnnotatedPrivateMethod = aBean;
}
public void setTransactionAspect(TransactionAspectSupport transactionAspect) {
this.txManager = (CallCountingTransactionManager) transactionAspect.getTransactionManager();
}
@Override
protected String[] getConfigPaths() {
return new String[] { "TransactionAspectTests-context.xml" };
}
@Test
public void testCommitOnAnnotatedClass() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
@@ -64,7 +74,6 @@ public class TransactionAspectTests {
assertEquals(1, txManager.commits);
}
@Test
public void testCommitOnAnnotatedProtectedMethod() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
@@ -72,7 +81,6 @@ public class TransactionAspectTests {
assertEquals(1, txManager.commits);
}
@Test
public void testCommitOnAnnotatedPrivateMethod() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
@@ -80,7 +88,6 @@ public class TransactionAspectTests {
assertEquals(1, txManager.commits);
}
@Test
public void testNoCommitOnNonAnnotatedNonPublicMethodInTransactionalType() throws Throwable {
txManager.clear();
assertEquals(0,txManager.begun);
@@ -88,7 +95,6 @@ public class TransactionAspectTests {
assertEquals(0,txManager.begun);
}
@Test
public void testCommitOnAnnotatedMethod() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
@@ -96,7 +102,6 @@ public class TransactionAspectTests {
assertEquals(1, txManager.commits);
}
@Test
public void testNotTransactional() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
@@ -104,7 +109,6 @@ public class TransactionAspectTests {
assertEquals(0, txManager.begun);
}
@Test
public void testDefaultCommitOnAnnotatedClass() throws Throwable {
final Exception ex = new Exception();
try {
@@ -121,7 +125,6 @@ public class TransactionAspectTests {
}
}
@Test
public void testDefaultRollbackOnAnnotatedClass() throws Throwable {
final RuntimeException ex = new RuntimeException();
try {
@@ -138,11 +141,10 @@ public class TransactionAspectTests {
}
}
@Test
public void testDefaultCommitOnSubclassOfAnnotatedClass() throws Throwable {
final Exception ex = new Exception();
try {
testRollback(new TransactionOperationCallback() {
testRollback(new TransactionOperationCallback() {
@Override
public Object performTransactionalOperation() throws Throwable {
return new SubclassOfClassWithTransactionalAnnotation().echo(ex);
@@ -155,7 +157,6 @@ public class TransactionAspectTests {
}
}
@Test
public void testDefaultCommitOnSubclassOfClassWithTransactionalMethodAnnotated() throws Throwable {
final Exception ex = new Exception();
try {
@@ -172,7 +173,6 @@ public class TransactionAspectTests {
}
}
@Test
public void testDefaultCommitOnImplementationOfAnnotatedInterface() throws Throwable {
final Exception ex = new Exception();
testNotTransactional(new TransactionOperationCallback() {
@@ -185,19 +185,16 @@ public class TransactionAspectTests {
/**
* Note: resolution does not occur. Thus we can't make a class transactional if
* it implements a transactionally annotated interface. This behavior could only
* it implements a transactionally annotated interface. This behaviour could only
* be changed in AbstractFallbackTransactionAttributeSource in Spring proper.
* See SPR-14322.
*/
@Test
public void testDoesNotResolveTxAnnotationOnMethodFromClassImplementingAnnotatedInterface() throws Exception {
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
Method method = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class);
TransactionAttribute ta = atas.getTransactionAttribute(method, ImplementsAnnotatedInterface.class);
Method m = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class);
TransactionAttribute ta = atas.getTransactionAttribute(m, ImplementsAnnotatedInterface.class);
assertNull(ta);
}
@Test
public void testDefaultRollbackOnImplementationOfAnnotatedInterface() throws Throwable {
final Exception rollbackProvokingException = new RuntimeException();
testNotTransactional(new TransactionOperationCallback() {
@@ -240,19 +237,15 @@ public class TransactionAspectTests {
private interface TransactionOperationCallback {
Object performTransactionalOperation() throws Throwable;
}
public static class SubclassOfClassWithTransactionalAnnotation extends TransactionalAnnotationOnlyOnClassWithNoInterface {
}
public static class SubclassOfClassWithTransactionalMethodAnnotation extends MethodAnnotationOnClassWithNoInterface {
}
public static class ImplementsAnnotatedInterface implements ITransactional {
@Override
@@ -264,7 +257,6 @@ public class TransactionAspectTests {
}
}
public static class NotTransactional {
public void noop() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -237,7 +237,6 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
Closure beans = new Closure(this) {
@Override
public Object call(Object[] args) {
invokeBeanDefiningClosure((Closure) args[0]);
return null;
@@ -304,7 +303,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
Collection constructorArgs = null;
if (!ObjectUtils.isEmpty(args)) {
int index = args.length;
Object lastArg = args[index - 1];
Object lastArg = args[index-1];
if (lastArg instanceof Closure) {
callable = (Closure) lastArg;
index--;
@@ -381,8 +380,10 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
refName = args[0].toString();
}
boolean parentRef = false;
if (args.length > 1 && args[1] instanceof Boolean) {
parentRef = (Boolean) args[1];
if (args.length > 1) {
if (args[1] instanceof Boolean) {
parentRef = (Boolean) args[1];
}
}
return new RuntimeBeanReference(refName, parentRef);
}
@@ -409,7 +410,12 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
private boolean addDeferredProperty(String property, Object newValue) {
if (newValue instanceof List || newValue instanceof Map) {
if (newValue instanceof List) {
this.deferredProperties.put(this.currentBeanDefinition.getBeanName() + '.' + property,
new DeferredProperty(this.currentBeanDefinition, property, newValue));
return true;
}
else if (newValue instanceof Map) {
this.deferredProperties.put(this.currentBeanDefinition.getBeanName() + '.' + property,
new DeferredProperty(this.currentBeanDefinition, property, newValue));
return true;
@@ -450,14 +456,14 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
* @return the bean definition wrapper
*/
private GroovyBeanDefinitionWrapper invokeBeanDefiningMethod(String beanName, Object[] args) {
boolean hasClosureArgument = (args[args.length - 1] instanceof Closure);
boolean hasClosureArgument = args[args.length - 1] instanceof Closure;
if (args[0] instanceof Class) {
Class<?> beanClass = (Class<?>) args[0];
Class<?> beanClass = (args[0] instanceof Class ? (Class<?>) args[0] : args[0].getClass());
if (args.length >= 1) {
if (hasClosureArgument) {
if (args.length - 1 != 1) {
if (args.length-1 != 1) {
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(
beanName, beanClass, resolveConstructorArguments(args, 1, args.length - 1));
beanName, beanClass, resolveConstructorArguments(args,1,args.length-1));
}
else {
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, beanClass);
@@ -465,7 +471,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
else {
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(
beanName, beanClass, resolveConstructorArguments(args, 1, args.length));
beanName, beanClass, resolveConstructorArguments(args,1,args.length));
}
}
@@ -477,7 +483,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
else if (args[0] instanceof Map) {
// named constructor arguments
if (args.length > 1 && args[1] instanceof Class) {
List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length);
List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length-1 : args.length);
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, (Class)args[1], constructorArgs);
Map namedArgs = (Map)args[0];
for (Object o : namedArgs.keySet()) {
@@ -513,18 +519,18 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
this.currentBeanDefinition.getBeanDefinition().setAbstract(true);
}
else {
List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length - 1 : args.length);
List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length-1 : args.length);
currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, null, constructorArgs);
}
if (hasClosureArgument) {
Closure callable = (Closure) args[args.length - 1];
Closure callable = (Closure)args[args.length-1];
callable.setDelegate(this);
callable.setResolveStrategy(Closure.DELEGATE_FIRST);
callable.call(this.currentBeanDefinition);
callable.call(new Object[]{currentBeanDefinition});
}
GroovyBeanDefinitionWrapper beanDefinition = this.currentBeanDefinition;
GroovyBeanDefinitionWrapper beanDefinition = currentBeanDefinition;
this.currentBeanDefinition = null;
beanDefinition.getBeanDefinition().setAttribute(GroovyBeanDefinitionWrapper.class.getName(), beanDefinition);
getRegistry().registerBeanDefinition(beanName, beanDefinition.getBeanDefinition());
@@ -812,17 +818,14 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
return retVal;
}
@Override
public Object invokeMethod(String name, Object args) {
return InvokerHelper.invokeMethod(this.propertyValue, name, args);
}
@Override
public Object getProperty(String name) {
return InvokerHelper.getProperty(this.propertyValue, name);
}
@Override
public void setProperty(String name, Object value) {
InvokerHelper.setProperty(this.propertyValue, name, value);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -162,7 +162,6 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
}
@Override
public Object getProperty(String property) {
if (this.definitionWrapper.isReadableProperty(property)) {
return this.definitionWrapper.getPropertyValue(property);
@@ -173,7 +172,6 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
return super.getProperty(property);
}
@Override
public void setProperty(String property, Object newValue) {
if (PARENT.equals(property)) {
setParent(newValue);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -55,10 +55,10 @@ import org.springframework.util.StringUtils;
* as String arrays are converted in such a format if the array itself is not
* assignable.
*
* @author Juergen Hoeller
* @author Stephane Nicoll
* @author Rod Johnson
* @author Juergen Hoeller
* @author Rob Harrop
* @author Stephane Nicoll
* @since 4.2
* @see #registerCustomEditor
* @see #setPropertyValues
@@ -96,7 +96,9 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
Object rootObject;
/** Map with cached nested Accessors: nested path -> Accessor instance */
/**
* Map with cached nested Accessors: nested path -> Accessor instance.
*/
private Map<String, AbstractNestablePropertyAccessor> nestedPropertyAccessors;
@@ -282,212 +284,198 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
}
}
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
if (tokens.keys != null) {
processKeyedProperty(tokens, pv);
}
else {
processLocalProperty(tokens, pv);
}
}
@SuppressWarnings("unchecked")
private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) {
Object propValue = getPropertyHoldingValue(tokens);
String lastKey = tokens.keys[tokens.keys.length - 1];
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
String propertyName = tokens.canonicalName;
String actualName = tokens.actualName;
if (propValue.getClass().isArray()) {
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
Class<?> requiredType = propValue.getClass().getComponentType();
int arrayIndex = Integer.parseInt(lastKey);
Object oldValue = null;
if (tokens.keys != null) {
// Apply indexes and map keys: fetch value for all keys but the last one.
PropertyTokenHolder getterTokens = new PropertyTokenHolder();
getterTokens.canonicalName = tokens.canonicalName;
getterTokens.actualName = tokens.actualName;
getterTokens.keys = new String[tokens.keys.length - 1];
System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);
Object propValue;
try {
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
oldValue = Array.get(propValue, arrayIndex);
}
Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
requiredType, ph.nested(tokens.keys.length));
int length = Array.getLength(propValue);
if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
Class<?> componentType = propValue.getClass().getComponentType();
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
System.arraycopy(propValue, 0, newArray, 0, length);
setPropertyValue(tokens.actualName, newArray);
propValue = getPropertyValue(tokens.actualName);
}
Array.set(propValue, arrayIndex, convertedValue);
propValue = getPropertyValue(getterTokens);
}
catch (IndexOutOfBoundsException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
"Invalid array index in property path '" + tokens.canonicalName + "'", ex);
}
}
else if (propValue instanceof List) {
PropertyHandler ph = getPropertyHandler(tokens.actualName);
Class<?> requiredType = ph.getCollectionType(tokens.keys.length);
List<Object> list = (List<Object>) propValue;
int index = Integer.parseInt(lastKey);
Object oldValue = null;
if (isExtractOldValueForEditor() && index < list.size()) {
oldValue = list.get(index);
}
Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
requiredType, ph.nested(tokens.keys.length));
int size = list.size();
if (index >= size && index < this.autoGrowCollectionLimit) {
for (int i = size; i < index; i++) {
try {
list.add(null);
}
catch (NullPointerException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
"Cannot set element with index " + index + " in List of size " +
size + ", accessed using property path '" + tokens.canonicalName +
"': List does not support filling up gaps with null elements");
}
}
list.add(convertedValue);
}
else {
try {
list.set(index, convertedValue);
}
catch (IndexOutOfBoundsException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
"Invalid list index in property path '" + tokens.canonicalName + "'", ex);
}
}
}
else if (propValue instanceof Map) {
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);
Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);
Map<Object, Object> map = (Map<Object, Object>) propValue;
// IMPORTANT: Do not pass full property name in here - property editors
// must not kick in for map keys but rather only for map values.
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
Object convertedMapKey = convertIfNecessary(null, null, lastKey, mapKeyType, typeDescriptor);
Object oldValue = null;
if (isExtractOldValueForEditor()) {
oldValue = map.get(convertedMapKey);
}
// Pass full property name and old value in here, since we want full
// conversion ability for map values.
Object convertedMapValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
mapValueType, ph.nested(tokens.keys.length));
map.put(convertedMapKey, convertedMapValue);
}
else {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
"Property referenced in indexed property path '" + tokens.canonicalName +
"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
}
}
private Object getPropertyHoldingValue(PropertyTokenHolder tokens) {
// Apply indexes and map keys: fetch value for all keys but the last one.
PropertyTokenHolder getterTokens = new PropertyTokenHolder();
getterTokens.canonicalName = tokens.canonicalName;
getterTokens.actualName = tokens.actualName;
getterTokens.keys = new String[tokens.keys.length - 1];
System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);
Object propValue;
try {
propValue = getPropertyValue(getterTokens);
}
catch (NotReadablePropertyException ex) {
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
"Cannot access indexed value in property referenced " +
"in indexed property path '" + tokens.canonicalName + "'", ex);
}
if (propValue == null) {
// null map value case
if (isAutoGrowNestedPaths()) {
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
propValue = setDefaultValue(getterTokens);
}
else {
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + tokens.canonicalName,
catch (NotReadablePropertyException ex) {
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
"Cannot access indexed value in property referenced " +
"in indexed property path '" + tokens.canonicalName + "': returned null");
"in indexed property path '" + propertyName + "'", ex);
}
}
return propValue;
}
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
if (ph == null || !ph.isWritable()) {
if (pv.isOptional()) {
if (logger.isDebugEnabled()) {
logger.debug("Ignoring optional value for property '" + tokens.actualName +
"' - property not found on bean class [" + getRootClass().getName() + "]");
}
return;
}
else {
throw createNotWritablePropertyException(tokens.canonicalName);
}
}
Object oldValue = null;
try {
Object originalValue = pv.getValue();
Object valueToApply = originalValue;
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
if (pv.isConverted()) {
valueToApply = pv.getConvertedValue();
// Set value for last key.
String key = tokens.keys[tokens.keys.length - 1];
if (propValue == null) {
// null map value case
if (isAutoGrowNestedPaths()) {
// TODO: cleanup, this is pretty hacky
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
propValue = setDefaultValue(getterTokens);
}
else {
if (isExtractOldValueForEditor() && ph.isReadable()) {
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,
"Cannot access indexed value in property referenced " +
"in indexed property path '" + propertyName + "': returned null");
}
}
if (propValue.getClass().isArray()) {
PropertyHandler ph = getLocalPropertyHandler(actualName);
Class<?> requiredType = propValue.getClass().getComponentType();
int arrayIndex = Integer.parseInt(key);
Object oldValue = null;
try {
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
oldValue = Array.get(propValue, arrayIndex);
}
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
requiredType, ph.nested(tokens.keys.length));
int length = Array.getLength(propValue);
if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
Class<?> componentType = propValue.getClass().getComponentType();
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
System.arraycopy(propValue, 0, newArray, 0, length);
setPropertyValue(actualName, newArray);
propValue = getPropertyValue(actualName);
}
Array.set(propValue, arrayIndex, convertedValue);
}
catch (IndexOutOfBoundsException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Invalid array index in property path '" + propertyName + "'", ex);
}
}
else if (propValue instanceof List) {
PropertyHandler ph = getPropertyHandler(actualName);
Class<?> requiredType = ph.getCollectionType(tokens.keys.length);
List<Object> list = (List<Object>) propValue;
int index = Integer.parseInt(key);
Object oldValue = null;
if (isExtractOldValueForEditor() && index < list.size()) {
oldValue = list.get(index);
}
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
requiredType, ph.nested(tokens.keys.length));
int size = list.size();
if (index >= size && index < this.autoGrowCollectionLimit) {
for (int i = size; i < index; i++) {
try {
oldValue = ph.getValue();
list.add(null);
}
catch (Exception ex) {
if (ex instanceof PrivilegedActionException) {
ex = ((PrivilegedActionException) ex).getException();
}
if (logger.isDebugEnabled()) {
logger.debug("Could not read previous value of property '" +
this.nestedPath + tokens.canonicalName + "'", ex);
}
catch (NullPointerException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Cannot set element with index " + index + " in List of size " +
size + ", accessed using property path '" + propertyName +
"': List does not support filling up gaps with null elements");
}
}
valueToApply = convertForProperty(
tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
list.add(convertedValue);
}
else {
try {
list.set(index, convertedValue);
}
catch (IndexOutOfBoundsException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Invalid list index in property path '" + propertyName + "'", ex);
}
}
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
ph.setValue(this.wrappedObject, valueToApply);
}
catch (TypeMismatchException ex) {
throw ex;
}
catch (InvocationTargetException ex) {
PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
this.rootObject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
if (ex.getTargetException() instanceof ClassCastException) {
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
else if (propValue instanceof Map) {
PropertyHandler ph = getLocalPropertyHandler(actualName);
Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);
Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);
Map<Object, Object> map = (Map<Object, Object>) propValue;
// IMPORTANT: Do not pass full property name in here - property editors
// must not kick in for map keys but rather only for map values.
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor);
Object oldValue = null;
if (isExtractOldValueForEditor()) {
oldValue = map.get(convertedMapKey);
}
// Pass full property name and old value in here, since we want full
// conversion ability for map values.
Object convertedMapValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
mapValueType, ph.nested(tokens.keys.length));
map.put(convertedMapKey, convertedMapValue);
}
else {
Throwable cause = ex.getTargetException();
if (cause instanceof UndeclaredThrowableException) {
// May happen e.g. with Groovy-generated methods
cause = cause.getCause();
}
throw new MethodInvocationException(propertyChangeEvent, cause);
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Property referenced in indexed property path '" + propertyName +
"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
}
}
catch (Exception ex) {
PropertyChangeEvent pce = new PropertyChangeEvent(
this.rootObject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
throw new MethodInvocationException(pce, ex);
else {
PropertyHandler ph = getLocalPropertyHandler(actualName);
if (ph == null || !ph.isWritable()) {
if (pv.isOptional()) {
if (logger.isDebugEnabled()) {
logger.debug("Ignoring optional value for property '" + actualName +
"' - property not found on bean class [" + getRootClass().getName() + "]");
}
return;
}
else {
throw createNotWritablePropertyException(propertyName);
}
}
Object oldValue = null;
try {
Object originalValue = pv.getValue();
Object valueToApply = originalValue;
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
if (pv.isConverted()) {
valueToApply = pv.getConvertedValue();
}
else {
if (isExtractOldValueForEditor() && ph.isReadable()) {
try {
oldValue = ph.getValue();
}
catch (Exception ex) {
if (ex instanceof PrivilegedActionException) {
ex = ((PrivilegedActionException) ex).getException();
}
if (logger.isDebugEnabled()) {
logger.debug("Could not read previous value of property '" +
this.nestedPath + propertyName + "'", ex);
}
}
}
valueToApply = convertForProperty(
propertyName, oldValue, originalValue, ph.toTypeDescriptor());
}
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
ph.setValue(this.wrappedObject, valueToApply);
}
catch (TypeMismatchException ex) {
throw ex;
}
catch (InvocationTargetException ex) {
PropertyChangeEvent propertyChangeEvent =
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
if (ex.getTargetException() instanceof ClassCastException) {
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
}
else {
Throwable cause = ex.getTargetException();
if (cause instanceof UndeclaredThrowableException) {
// May happen e.g. with Groovy-generated methods
cause = cause.getCause();
}
throw new MethodInvocationException(propertyChangeEvent, cause);
}
}
catch (Exception ex) {
PropertyChangeEvent pce =
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
throw new MethodInvocationException(pce, ex);
}
}
}
@@ -985,6 +973,9 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
}
/**
* Handle a given property.
*/
protected abstract static class PropertyHandler {
private final Class<?> propertyType;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -311,23 +311,23 @@ public abstract class BeanUtils {
public static Method resolveSignature(String signature, Class<?> clazz) {
Assert.hasText(signature, "'signature' must not be empty");
Assert.notNull(clazz, "Class must not be null");
int startParen = signature.indexOf('(');
int endParen = signature.indexOf(')');
if (startParen > -1 && endParen == -1) {
int firstParen = signature.indexOf("(");
int lastParen = signature.indexOf(")");
if (firstParen > -1 && lastParen == -1) {
throw new IllegalArgumentException("Invalid method signature '" + signature +
"': expected closing ')' for args list");
}
else if (startParen == -1 && endParen > -1) {
else if (lastParen > -1 && firstParen == -1) {
throw new IllegalArgumentException("Invalid method signature '" + signature +
"': expected opening '(' for args list");
}
else if (startParen == -1 && endParen == -1) {
else if (firstParen == -1 && lastParen == -1) {
return findMethodWithMinimalParameters(clazz, signature);
}
else {
String methodName = signature.substring(0, startParen);
String methodName = signature.substring(0, firstParen);
String[] parameterTypeNames =
StringUtils.commaDelimitedListToStringArray(signature.substring(startParen + 1, endParen));
StringUtils.commaDelimitedListToStringArray(signature.substring(firstParen + 1, lastParen));
Class<?>[] parameterTypes = new Class<?>[parameterTypeNames.length];
for (int i = 0; i < parameterTypeNames.length; i++) {
String parameterTypeName = parameterTypeNames[i].trim();
@@ -506,14 +506,13 @@ public abstract class BeanUtils {
/**
* Check if the given type represents a "simple" value type:
* a primitive, an enum, a String or other CharSequence, a Number, a Date,
* a primitive, a String or other CharSequence, a Number, a Date,
* a URI, a URL, a Locale or a Class.
* @param clazz the type to check
* @return whether the given type represents a "simple" value type
*/
public static boolean isSimpleValueType(Class<?> clazz) {
return (ClassUtils.isPrimitiveOrWrapper(clazz) ||
Enum.class.isAssignableFrom(clazz) ||
return (ClassUtils.isPrimitiveOrWrapper(clazz) || clazz.isEnum() ||
CharSequence.class.isAssignableFrom(clazz) ||
Number.class.isAssignableFrom(clazz) ||
Date.class.isAssignableFrom(clazz) ||
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -224,7 +224,10 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
@Override
protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) {
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName);
return (pd != null ? new BeanPropertyHandler(pd) : null);
if (pd != null) {
return new BeanPropertyHandler(pd);
}
return null;
}
@Override
@@ -235,7 +238,8 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
@Override
protected NotWritablePropertyException createNotWritablePropertyException(String propertyName) {
PropertyMatches matches = PropertyMatches.forProperty(propertyName, getRootClass());
throw new NotWritablePropertyException(getRootClass(), getNestedPath() + propertyName,
throw new NotWritablePropertyException(
getRootClass(), getNestedPath() + propertyName,
matches.buildErrorMessage(), matches.getPossibleMatches());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -339,10 +339,10 @@ public class CachedIntrospectionResults {
PropertyDescriptor getPropertyDescriptor(String name) {
PropertyDescriptor pd = this.propertyDescriptorCache.get(name);
if (pd == null && StringUtils.hasLength(name)) {
// Same lenient fallback checking as in Property...
pd = this.propertyDescriptorCache.get(StringUtils.uncapitalize(name));
// Same lenient fallback checking as in PropertyTypeDescriptor...
pd = this.propertyDescriptorCache.get(name.substring(0, 1).toLowerCase() + name.substring(1));
if (pd == null) {
pd = this.propertyDescriptorCache.get(StringUtils.capitalize(name));
pd = this.propertyDescriptorCache.get(name.substring(0, 1).toUpperCase() + name.substring(1));
}
}
return (pd == null || pd instanceof GenericTypeAwarePropertyDescriptor ? pd :
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -76,8 +76,8 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
Field field = ReflectionUtils.findField(getWrappedClass(), propertyName);
if (field != null) {
propertyHandler = new FieldPropertyHandler(field);
this.fieldMap.put(propertyName, propertyHandler);
}
this.fieldMap.put(propertyName, propertyHandler);
}
return propertyHandler;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@ public interface Mergeable {
* @param parent the object to merge with
* @return the result of the merge operation
* @throws IllegalArgumentException if the supplied parent is {@code null}
* @throws IllegalStateException if merging is not enabled for this instance
* @exception IllegalStateException if merging is not enabled for this instance
* (i.e. {@code mergeEnabled} equals {@code false}).
*/
Object merge(Object parent);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -262,7 +262,7 @@ public class MutablePropertyValues implements PropertyValues, Serializable {
/**
* Get the raw property value, if any.
* @param propertyName the name to search for
* @return the raw property value, or {@code null} if none found
* @return the raw property value, or {@code null}
* @since 4.0
* @see #getPropertyValue(String)
* @see PropertyValue#getValue()
@@ -283,7 +283,11 @@ public class MutablePropertyValues implements PropertyValues, Serializable {
for (PropertyValue newPv : this.propertyValueList) {
// if there wasn't an old one, add it
PropertyValue pvOld = old.getPropertyValue(newPv.getName());
if (pvOld == null || !pvOld.equals(newPv)) {
if (pvOld == null) {
changes.addPropertyValue(newPv);
}
else if (!pvOld.equals(newPv)) {
// it's changed
changes.addPropertyValue(newPv);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2012 the original author 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,8 @@ package org.springframework.beans;
import java.beans.PropertyChangeEvent;
import org.springframework.core.ErrorCoded;
/**
* Superclass for exceptions related to a property access,
* such as type mismatch or invocation target exception.
@@ -25,8 +27,8 @@ import java.beans.PropertyChangeEvent;
* @author Rod Johnson
* @author Juergen Hoeller
*/
@SuppressWarnings({"serial", "deprecation"})
public abstract class PropertyAccessException extends BeansException implements org.springframework.core.ErrorCoded {
@SuppressWarnings("serial")
public abstract class PropertyAccessException extends BeansException implements ErrorCoded {
private transient PropertyChangeEvent propertyChangeEvent;
@@ -75,10 +77,4 @@ public abstract class PropertyAccessException extends BeansException implements
return (this.propertyChangeEvent != null ? this.propertyChangeEvent.getNewValue() : null);
}
/**
* Return a corresponding error code for this type of exception.
*/
@Override
public abstract String getErrorCode();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -81,6 +81,8 @@ public interface PropertyAccessor {
* (may be a nested path and/or an indexed/mapped property)
* @return the property type for the particular property,
* or {@code null} if not determinable
* @throws InvalidPropertyException if there is no such property or
* if the property isn't readable
* @throws PropertyAccessException if the property was valid but the
* accessor method failed
*/
@@ -93,8 +95,8 @@ public interface PropertyAccessor {
* (may be a nested path and/or an indexed/mapped property)
* @return the property type for the particular property,
* or {@code null} if not determinable
* @throws PropertyAccessException if the property was valid but the
* accessor method failed
* @throws InvalidPropertyException if there is no such property or
* if the property isn't readable
*/
TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException;
@@ -75,7 +75,7 @@ class PropertyDescriptorUtils {
}
if (writeMethod != null) {
Class<?>[] params = writeMethod.getParameterTypes();
Class<?> params[] = writeMethod.getParameterTypes();
if (params.length != 1) {
throw new IntrospectionException("Bad write method arg count: " + writeMethod);
}
@@ -109,7 +109,7 @@ class PropertyDescriptorUtils {
Class<?> indexedPropertyType = null;
if (indexedReadMethod != null) {
Class<?>[] params = indexedReadMethod.getParameterTypes();
Class<?> params[] = indexedReadMethod.getParameterTypes();
if (params.length != 1) {
throw new IntrospectionException("Bad indexed read method arg count: " + indexedReadMethod);
}
@@ -123,7 +123,7 @@ class PropertyDescriptorUtils {
}
if (indexedWriteMethod != null) {
Class<?>[] params = indexedWriteMethod.getParameterTypes();
Class<?> params[] = indexedWriteMethod.getParameterTypes();
if (params.length != 2) {
throw new IntrospectionException("Bad indexed write method arg count: " + indexedWriteMethod);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -150,14 +150,14 @@ public abstract class PropertyMatches {
* @return the distance value
*/
private static int calculateStringDistance(String s1, String s2) {
if (s1.isEmpty()) {
if (s1.length() == 0) {
return s2.length();
}
if (s2.isEmpty()) {
if (s2.length() == 0) {
return s1.length();
}
int d[][] = new int[s1.length() + 1][s2.length() + 1];
int[][] d = new int[s1.length() + 1][s2.length() + 1];
for (int i = 0; i <= s1.length(); i++) {
d[i][0] = i;
}
@@ -166,17 +166,18 @@ public abstract class PropertyMatches {
}
for (int i = 1; i <= s1.length(); i++) {
char c1 = s1.charAt(i - 1);
char s_i = s1.charAt(i - 1);
for (int j = 1; j <= s2.length(); j++) {
int cost;
char c2 = s2.charAt(j - 1);
if (c1 == c2) {
char t_j = s2.charAt(j - 1);
if (s_i == t_j) {
cost = 0;
}
else {
cost = 1;
}
d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1), d[i - 1][j - 1] + cost);
d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1),
d[i - 1][j - 1] + cost);
}
}
@@ -189,23 +190,24 @@ public abstract class PropertyMatches {
private static class BeanPropertyMatches extends PropertyMatches {
public BeanPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
super(propertyName,
calculateMatches(propertyName, BeanUtils.getPropertyDescriptors(beanClass), maxDistance));
super(propertyName, calculateMatches(propertyName,
BeanUtils.getPropertyDescriptors(beanClass), maxDistance));
}
/**
* Generate possible property alternatives for the given property and class.
* Internally uses the {@code getStringDistance} method, which in turn uses
* the Levenshtein algorithm to determine the distance between two Strings.
* @param descriptors the JavaBeans property descriptors to search
* Generate possible property alternatives for the given property and
* class. Internally uses the {@code getStringDistance} method, which
* in turn uses the Levenshtein algorithm to determine the distance between
* two Strings.
* @param propertyDescriptors the JavaBeans property descriptors to search
* @param maxDistance the maximum distance to accept
*/
private static String[] calculateMatches(String name, PropertyDescriptor[] descriptors, int maxDistance) {
private static String[] calculateMatches(String propertyName, PropertyDescriptor[] propertyDescriptors, int maxDistance) {
List<String> candidates = new ArrayList<String>();
for (PropertyDescriptor pd : descriptors) {
for (PropertyDescriptor pd : propertyDescriptors) {
if (pd.getWriteMethod() != null) {
String possibleAlternative = pd.getName();
if (calculateStringDistance(name, possibleAlternative) <= maxDistance) {
if (calculateStringDistance(propertyName, possibleAlternative) <= maxDistance) {
candidates.add(possibleAlternative);
}
}
@@ -214,16 +216,21 @@ public abstract class PropertyMatches {
return StringUtils.toStringArray(candidates);
}
@Override
public String buildErrorMessage() {
StringBuilder msg = new StringBuilder(160);
msg.append("Bean property '").append(getPropertyName()).append(
"' is not writable or has an invalid setter method. ");
if (!ObjectUtils.isEmpty(getPossibleMatches())) {
appendHintMessage(msg);
String propertyName = getPropertyName();
String[] possibleMatches = getPossibleMatches();
StringBuilder msg = new StringBuilder();
msg.append("Bean property '");
msg.append(propertyName);
msg.append("' is not writable or has an invalid setter method. ");
if (ObjectUtils.isEmpty(possibleMatches)) {
msg.append("Does the parameter type of the setter match the return type of the getter?");
}
else {
msg.append("Does the parameter type of the setter match the return type of the getter?");
appendHintMessage(msg);
}
return msg.toString();
}
@@ -236,13 +243,13 @@ public abstract class PropertyMatches {
super(propertyName, calculateMatches(propertyName, beanClass, maxDistance));
}
private static String[] calculateMatches(final String name, Class<?> clazz, final int maxDistance) {
private static String[] calculateMatches(final String propertyName, Class<?> beanClass, final int maxDistance) {
final List<String> candidates = new ArrayList<String>();
ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() {
ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
String possibleAlternative = field.getName();
if (calculateStringDistance(name, possibleAlternative) <= maxDistance) {
if (calculateStringDistance(propertyName, possibleAlternative) <= maxDistance) {
candidates.add(possibleAlternative);
}
}
@@ -253,10 +260,14 @@ public abstract class PropertyMatches {
@Override
public String buildErrorMessage() {
StringBuilder msg = new StringBuilder(80);
msg.append("Bean property '").append(getPropertyName()).append("' has no matching field.");
if (!ObjectUtils.isEmpty(getPossibleMatches())) {
msg.append(' ');
String propertyName = getPropertyName();
String[] possibleMatches = getPossibleMatches();
StringBuilder msg = new StringBuilder();
msg.append("Bean property '");
msg.append(propertyName);
msg.append("' has no matching field. ");
if (!ObjectUtils.isEmpty(possibleMatches)) {
appendHintMessage(msg);
}
return msg.toString();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,7 +35,6 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.util.ClassUtils;
import org.springframework.util.NumberUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
@@ -325,7 +324,7 @@ class TypeConverterDelegate {
if (Enum.class == requiredType) {
// target type is declared as raw enum, treat the trimmed value as <enum.fqn>.FIELD_NAME
int index = trimmedValue.lastIndexOf('.');
int index = trimmedValue.lastIndexOf(".");
if (index > - 1) {
String enumType = trimmedValue.substring(0, index);
String fieldName = trimmedValue.substring(index + 1);
@@ -354,7 +353,6 @@ class TypeConverterDelegate {
// to be checked, hence we don't return it right away.
try {
Field enumField = requiredType.getField(trimmedValue);
ReflectionUtils.makeAccessible(enumField);
convertedValue = enumField.get(null);
}
catch (Throwable ex) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@ public class TypeMismatchException extends PropertyAccessException {
/**
* Create a new {@code TypeMismatchException}.
* Create a new TypeMismatchException.
* @param propertyChangeEvent the PropertyChangeEvent that resulted in the problem
* @param requiredType the required target type
*/
@@ -50,7 +50,7 @@ public class TypeMismatchException extends PropertyAccessException {
}
/**
* Create a new {@code TypeMismatchException}.
* Create a new TypeMismatchException.
* @param propertyChangeEvent the PropertyChangeEvent that resulted in the problem
* @param requiredType the required target type (or {@code null} if not known)
* @param cause the root cause (may be {@code null})
@@ -69,7 +69,7 @@ public class TypeMismatchException extends PropertyAccessException {
}
/**
* Create a new {@code TypeMismatchException} without a {@code PropertyChangeEvent}.
* Create a new TypeMismatchException without PropertyChangeEvent.
* @param value the offending value that couldn't be converted (may be {@code null})
* @param requiredType the required target type (or {@code null} if not known)
*/
@@ -78,7 +78,7 @@ public class TypeMismatchException extends PropertyAccessException {
}
/**
* Create a new {@code TypeMismatchException} without a {@code PropertyChangeEvent}.
* Create a new TypeMismatchException without PropertyChangeEvent.
* @param value the offending value that couldn't be converted (may be {@code null})
* @param requiredType the required target type (or {@code null} if not known)
* @param cause the root cause (may be {@code null})
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -75,7 +75,7 @@ public class BeanDefinitionStoreException extends FatalBeanException {
/**
* Create a new BeanDefinitionStoreException.
* @param resourceDescription description of the resource that the bean definition came from
* @param beanName the name of the bean
* @param beanName the name of the bean requested
* @param msg the detail message (appended to an introductory message that indicates
* the resource and the name of the bean)
*/
@@ -86,28 +86,28 @@ public class BeanDefinitionStoreException extends FatalBeanException {
/**
* Create a new BeanDefinitionStoreException.
* @param resourceDescription description of the resource that the bean definition came from
* @param beanName the name of the bean
* @param beanName the name of the bean requested
* @param msg the detail message (appended to an introductory message that indicates
* the resource and the name of the bean)
* @param cause the root cause (may be {@code null})
*/
public BeanDefinitionStoreException(String resourceDescription, String beanName, String msg, Throwable cause) {
super("Invalid bean definition with name '" + beanName + "' defined in " + resourceDescription + ": " + msg,
cause);
super("Invalid bean definition with name '" + beanName + "' defined in " + resourceDescription + ": " + msg, cause);
this.resourceDescription = resourceDescription;
this.beanName = beanName;
}
/**
* Return the description of the resource that the bean definition came from, if available.
* Return the description of the resource that the bean
* definition came from, if any.
*/
public String getResourceDescription() {
return this.resourceDescription;
}
/**
* Return the name of the bean, if available.
* Return the name of the bean requested, if any.
*/
public String getBeanName() {
return this.beanName;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -158,22 +158,6 @@ public interface BeanFactory {
*/
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
/**
* Return an instance, which may be shared or independent, of the specified bean.
* <p>Allows for specifying explicit constructor arguments / factory method arguments,
* overriding the specified default arguments (if any) in the bean definition.
* @param name the name of the bean to retrieve
* @param args arguments to use when creating a bean instance using explicit arguments
* (only applied when creating a new instance as opposed to retrieving an existing one)
* @return an instance of the bean
* @throws NoSuchBeanDefinitionException if there is no such bean definition
* @throws BeanDefinitionStoreException if arguments have been given but
* the affected bean isn't a prototype
* @throws BeansException if the bean could not be created
* @since 2.5
*/
Object getBean(String name, Object... args) throws BeansException;
/**
* Return the bean instance that uniquely matches the given object type, if any.
* <p>This method goes into {@link ListableBeanFactory} by-type lookup territory
@@ -191,6 +175,22 @@ public interface BeanFactory {
*/
<T> T getBean(Class<T> requiredType) throws BeansException;
/**
* Return an instance, which may be shared or independent, of the specified bean.
* <p>Allows for specifying explicit constructor arguments / factory method arguments,
* overriding the specified default arguments (if any) in the bean definition.
* @param name the name of the bean to retrieve
* @param args arguments to use when creating a bean instance using explicit arguments
* (only applied when creating a new instance as opposed to retrieving an existing one)
* @return an instance of the bean
* @throws NoSuchBeanDefinitionException if there is no such bean definition
* @throws BeanDefinitionStoreException if arguments have been given but
* the affected bean isn't a prototype
* @throws BeansException if the bean could not be created
* @since 2.5
*/
Object getBean(String name, Object... args) throws BeansException;
/**
* Return an instance, which may be shared or independent, of the specified bean.
* <p>Allows for specifying explicit constructor arguments / factory method arguments,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -147,7 +147,14 @@ public abstract class BeanFactoryUtils {
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
String[] parentResult = beanNamesForTypeIncludingAncestors(
(ListableBeanFactory) hbf.getParentBeanFactory(), type);
result = mergeNamesWithParent(result, parentResult, hbf);
List<String> resultList = new ArrayList<String>();
resultList.addAll(Arrays.asList(result));
for (String beanName : parentResult) {
if (!resultList.contains(beanName) && !hbf.containsLocalBean(beanName)) {
resultList.add(beanName);
}
}
result = StringUtils.toStringArray(resultList);
}
}
return result;
@@ -173,7 +180,14 @@ public abstract class BeanFactoryUtils {
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
String[] parentResult = beanNamesForTypeIncludingAncestors(
(ListableBeanFactory) hbf.getParentBeanFactory(), type);
result = mergeNamesWithParent(result, parentResult, hbf);
List<String> resultList = new ArrayList<String>();
resultList.addAll(Arrays.asList(result));
for (String beanName : parentResult) {
if (!resultList.contains(beanName) && !hbf.containsLocalBean(beanName)) {
resultList.add(beanName);
}
}
result = StringUtils.toStringArray(resultList);
}
}
return result;
@@ -209,7 +223,14 @@ public abstract class BeanFactoryUtils {
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
String[] parentResult = beanNamesForTypeIncludingAncestors(
(ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
result = mergeNamesWithParent(result, parentResult, hbf);
List<String> resultList = new ArrayList<String>();
resultList.addAll(Arrays.asList(result));
for (String beanName : parentResult) {
if (!resultList.contains(beanName) && !hbf.containsLocalBean(beanName)) {
resultList.add(beanName);
}
}
result = StringUtils.toStringArray(resultList);
}
}
return result;
@@ -425,29 +446,6 @@ public abstract class BeanFactoryUtils {
return uniqueBean(type, beansOfType);
}
/**
* Merge the given bean names result with the given parent result.
* @param result the local bean name result
* @param parentResult the parent bean name result (possibly empty)
* @param hbf the local bean factory
* @return the merged result (possibly the local result as-is)
* @since 4.3.15
*/
private static String[] mergeNamesWithParent(String[] result, String[] parentResult, HierarchicalBeanFactory hbf) {
if (parentResult.length == 0) {
return result;
}
List<String> merged = new ArrayList<String>(result.length + parentResult.length);
merged.addAll(Arrays.asList(result));
for (String beanName : parentResult) {
if (!merged.contains(beanName) && !hbf.containsLocalBean(beanName)) {
merged.add(beanName);
}
}
return StringUtils.toStringArray(merged);
}
/**
* Extract a unique bean for the given type from the given Map of matching beans.
* @param type type of bean to match
@@ -457,11 +455,11 @@ public abstract class BeanFactoryUtils {
* @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found
*/
private static <T> T uniqueBean(Class<T> type, Map<String, T> matchingBeans) {
int count = matchingBeans.size();
if (count == 1) {
int nrFound = matchingBeans.size();
if (nrFound == 1) {
return matchingBeans.values().iterator().next();
}
else if (count > 1) {
else if (nrFound > 1) {
throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
}
else {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,8 +46,8 @@ public class CannotLoadBeanClassException extends FatalBeanException {
public CannotLoadBeanClassException(
String resourceDescription, String beanName, String beanClassName, ClassNotFoundException cause) {
super("Cannot find class [" + beanClassName + "] for bean with name '" + beanName + "'" +
(resourceDescription != null ? " defined in " + resourceDescription : ""), cause);
super("Cannot find class [" + beanClassName + "] for bean with name '" + beanName +
"' defined in " + resourceDescription, cause);
this.resourceDescription = resourceDescription;
this.beanName = beanName;
this.beanClassName = beanClassName;
@@ -64,9 +64,8 @@ public class CannotLoadBeanClassException extends FatalBeanException {
public CannotLoadBeanClassException(
String resourceDescription, String beanName, String beanClassName, LinkageError cause) {
super("Error loading class [" + beanClassName + "] for bean with name '" + beanName + "'" +
(resourceDescription != null ? " defined in " + resourceDescription : "") +
": problem with class file or dependent class", cause);
super("Error loading class [" + beanClassName + "] for bean with name '" + beanName +
"' defined in " + resourceDescription + ": problem with class file or dependent class", cause);
this.resourceDescription = resourceDescription;
this.beanName = beanName;
this.beanClassName = beanClassName;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2012 the original author 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,29 +17,27 @@
package org.springframework.beans.factory;
/**
* Interface to be implemented by beans that want to release resources on destruction.
* A {@link BeanFactory} will invoke the destroy method on individual destruction of a
* scoped bean. An {@link org.springframework.context.ApplicationContext} is supposed
* to dispose all of its singletons on shutdown, driven by the application lifecycle.
* Interface to be implemented by beans that want to release resources
* on destruction. A BeanFactory is supposed to invoke the destroy
* method if it disposes a cached singleton. An application context
* is supposed to dispose all of its singletons on close.
*
* <p>A Spring-managed bean may also implement Java's {@link AutoCloseable} interface
* for the same purpose. An alternative to implementing an interface is specifying a
* custom destroy method, for example in an XML bean definition. For a list of all
* bean lifecycle methods, see the {@link BeanFactory BeanFactory javadocs}.
* <p>An alternative to implementing DisposableBean is specifying a custom
* destroy-method, for example in an XML bean definition.
* For a list of all bean lifecycle methods, see the BeanFactory javadocs.
*
* @author Juergen Hoeller
* @since 12.08.2003
* @see InitializingBean
* @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName()
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons()
* @see org.springframework.context.ConfigurableApplicationContext#close()
* @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName
* @see org.springframework.context.ConfigurableApplicationContext#close
*/
public interface DisposableBean {
/**
* Invoked by the containing {@code BeanFactory} on destruction of a bean.
* @throws Exception in case of shutdown errors. Exceptions will get logged
* but not rethrown to allow other beans to release their resources as well.
* Invoked by a BeanFactory on destruction of a singleton.
* @throws Exception in case of shutdown errors.
* Exceptions will get logged but not rethrown to allow
* other beans to release their resources too.
*/
void destroy() throws Exception;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2012 the original author 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,34 +17,31 @@
package org.springframework.beans.factory;
/**
* Interface to be implemented by objects used within a {@link BeanFactory} which
* are themselves factories for individual objects. If a bean implements this
* interface, it is used as a factory for an object to expose, not directly as a
* bean instance that will be exposed itself.
* Interface to be implemented by objects used within a {@link BeanFactory}
* which are themselves factories. If a bean implements this interface,
* it is used as a factory for an object to expose, not directly as a bean
* instance that will be exposed itself.
*
* <p><b>NB: A bean that implements this interface cannot be used as a normal bean.</b>
* A FactoryBean is defined in a bean style, but the object exposed for bean
* references ({@link #getObject()}) is always the object that it creates.
* <p><b>NB: A bean that implements this interface cannot be used as a
* normal bean.</b> A FactoryBean is defined in a bean style, but the
* object exposed for bean references ({@link #getObject()} is always
* the object that it creates.
*
* <p>FactoryBeans can support singletons and prototypes, and can either create
* objects lazily on demand or eagerly on startup. The {@link SmartFactoryBean}
* interface allows for exposing more fine-grained behavioral metadata.
* <p>FactoryBeans can support singletons and prototypes, and can
* either create objects lazily on demand or eagerly on startup.
* The {@link SmartFactoryBean} interface allows for exposing
* more fine-grained behavioral metadata.
*
* <p>This interface is heavily used within the framework itself, for example for
* the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the
* {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for
* custom components as well; however, this is only common for infrastructure code.
* <p>This interface is heavily used within the framework itself, for
* example for the AOP {@link org.springframework.aop.framework.ProxyFactoryBean}
* or the {@link org.springframework.jndi.JndiObjectFactoryBean}.
* It can be used for application components as well; however,
* this is not common outside of infrastructure code.
*
* <p><b>{@code FactoryBean} is a programmatic contract. Implementations are not
* supposed to rely on annotation-driven injection or other reflective facilities.</b>
* {@link #getObjectType()} {@link #getObject()} invocations may arrive early in
* the bootstrap process, even ahead of any post-processor setup. If you need access
* other beans, implement {@link BeanFactoryAware} and obtain them programmatically.
*
* <p>Finally, FactoryBean objects participate in the containing BeanFactory's
* synchronization of bean creation. There is usually no need for internal
* synchronization other than for purposes of lazy initialization within the
* FactoryBean itself (or the like).
* <p><b>NOTE:</b> FactoryBean objects participate in the containing
* BeanFactory's synchronization of bean creation. There is usually no
* need for internal synchronization other than for purposes of lazy
* initialization within the FactoryBean itself (or the like).
*
* @author Rod Johnson
* @author Juergen Hoeller

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