mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
368 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4416e6cd4f | |||
| edba32b309 | |||
| 7efd54e243 | |||
| 319724f0b4 | |||
| 2b4c81e642 | |||
| fe6a9826c5 | |||
| 268657b6cb | |||
| 1dedb67fbc | |||
| bde4964af5 | |||
| 8a96d1a6ee | |||
| ef1748f694 | |||
| 14e5a02870 | |||
| 9c6df766cd | |||
| f913940402 | |||
| 72fe7ebc34 | |||
| 6fba8292f5 | |||
| d550ffb37f | |||
| 34d397efa9 | |||
| 32e5f57e64 | |||
| 741b4b229a | |||
| 0cb27f4bc5 | |||
| b1abe26b33 | |||
| 206655c2b4 | |||
| 1ae3eba89a | |||
| 8028eae786 | |||
| bda8f2b4cf | |||
| ce39146be8 | |||
| f2a4537b6c | |||
| 674169fe07 | |||
| 520ef9ec23 | |||
| 603cdea26e | |||
| 0ec99fdef7 | |||
| 6f58491b9c | |||
| 3716a8ef7d | |||
| 891ec56607 | |||
| dfe2234781 | |||
| 9534245660 | |||
| 8ae3aa7f59 | |||
| cead06a3d9 | |||
| 4a45af0038 | |||
| 949338009b | |||
| 1a1c72ce4b | |||
| 5f1592a61a | |||
| 648245b200 | |||
| 7301b58ec9 | |||
| 12598f8581 | |||
| 14616a445a | |||
| b4f1a4c6dc | |||
| 1cf38a98a4 | |||
| ac22b786be | |||
| 57c4eca039 | |||
| 53aab24690 | |||
| 74ad2081aa | |||
| f77bf2422e | |||
| c335e99e3f | |||
| 1f778530b5 | |||
| f717b55035 | |||
| 08842f3fdf | |||
| 2d5c5fc18e | |||
| 8c0e3040c2 | |||
| 749b65b0b2 | |||
| 99f9dce14a | |||
| 919d6ccb3b | |||
| 9a8f860318 | |||
| 631b07aef8 | |||
| de5b7a378b | |||
| f1d146f305 | |||
| cdd2324ab5 | |||
| 42d0470d94 | |||
| bdb742b8db | |||
| 09e2e5897d | |||
| 2410e29dda | |||
| 7566ceb5f2 | |||
| 9a6252d715 | |||
| 426f52b393 | |||
| 8c4e372558 | |||
| 522d136bbd | |||
| f636ccb5eb | |||
| 46c0e45130 | |||
| 624170f178 | |||
| edb0b0e84b | |||
| 81c259fe42 | |||
| 67142dcb0a | |||
| 261a863e8f | |||
| 9fe9e27189 | |||
| 76f3d6e501 | |||
| 3a89bc4b26 | |||
| 69a89b1bb0 | |||
| 1cd5071e6a | |||
| 8a6b095204 | |||
| 6634c19e6a | |||
| 60c1905cdd | |||
| 1a8629d408 | |||
| d90a36170a | |||
| b8ed2f4967 | |||
| 1c5cab2a40 | |||
| f053f60630 | |||
| d55c22ec85 | |||
| f27304d785 | |||
| 874a2a9ca2 | |||
| e6f4796779 | |||
| 46b24dbd33 | |||
| 5f2429429f | |||
| d52f584322 | |||
| da369aa826 | |||
| f0a53ae54e | |||
| b6da7e2795 | |||
| a521ef5cee | |||
| 4f60b98bca | |||
| e680e34620 | |||
| 474f1b03cd | |||
| 8c3868a8dd | |||
| c2303854d1 | |||
| 5be8301128 | |||
| a537eb3a6a | |||
| c1eac209c3 | |||
| 1af61ef1d5 | |||
| 47395f6b0a | |||
| 8570f607a7 | |||
| 786e217991 | |||
| 63e023173b | |||
| 5f8275a305 | |||
| 1e303ac1af | |||
| 14d3525a28 | |||
| c5f908b174 | |||
| c719c70ea9 | |||
| 425e5a066e | |||
| fcbd3b121b | |||
| d004b634a5 | |||
| 500d0da67d | |||
| 1b0ce200e0 | |||
| bf9702294d | |||
| 79e17dbfa0 | |||
| cc0a845653 | |||
| 78542777d6 | |||
| bb28d198f5 | |||
| e0fd54b8c2 | |||
| 56b7d7a94a | |||
| 67e76e9a8d | |||
| 98e890aae3 | |||
| 4b282a965c | |||
| 9154871a45 | |||
| 61b6d398a5 | |||
| c1ef552359 | |||
| eab69dbeec | |||
| 31a74b0ff6 | |||
| 5e7811a45d | |||
| d404473bc5 | |||
| 5331da6aff | |||
| 21eb8db5bc | |||
| defc1d3157 | |||
| 167329ce0c | |||
| 2dcbf4d618 | |||
| 624f81a5a3 | |||
| ab5f1256bf | |||
| b6073d9ac4 | |||
| 8543b91c50 | |||
| 6151e6d12a | |||
| eeae5fba95 | |||
| 0013a43237 | |||
| 42db41e007 | |||
| 86fc2dd556 | |||
| 8faf01f56d | |||
| 9c3a972dac | |||
| 6793765b0a | |||
| 8d304efad1 | |||
| 3310ab55e0 | |||
| 6a6a23f0a3 | |||
| fb12e234fc | |||
| 09251dfad1 | |||
| a106e06a89 | |||
| 3ffc3d442d | |||
| 3cb5828e21 | |||
| 227320dc81 | |||
| 1c4530f251 | |||
| 0e7b94f9e9 | |||
| 74fe1aea31 | |||
| 8ee2a2d18c | |||
| 499c858cd4 | |||
| 8105011368 | |||
| 0db2f79bdb | |||
| db9b6fa28e | |||
| 175aa86d79 | |||
| 98174e101f | |||
| a599b57a74 | |||
| e20c927c5e | |||
| c0eafa9ea1 | |||
| 597ef099d0 | |||
| 845a6b0b7d | |||
| 12c393eb6d | |||
| 3969467851 | |||
| 59604b1cd5 | |||
| d03fb8954b | |||
| d96b91a57b | |||
| ae06c3a6ab | |||
| e4ad2b352e | |||
| 2cafe9d73a | |||
| 3514242486 | |||
| 9cc86a3c80 | |||
| 4ae893e110 | |||
| 3370f8b1b1 | |||
| 098d7c7465 | |||
| 4a569e6b1a | |||
| 84310c8a11 | |||
| eac4881809 | |||
| 8edb7a18cc | |||
| 17e492e641 | |||
| 7df25764af | |||
| b92e4299b8 | |||
| 709ac28f29 | |||
| 96d6963d61 | |||
| 1aff833282 | |||
| 8281b93596 | |||
| a9ff1403c3 | |||
| 6bb6b6e6b5 | |||
| 5053fdc8c9 | |||
| 5e5add4862 | |||
| cc81aae8c1 | |||
| 88730bdaa5 | |||
| b4e48d6749 | |||
| 809a5f59b3 | |||
| 19859fdb35 | |||
| c376ee92cd | |||
| d1b1770eba | |||
| f15a5fef8e | |||
| f0449c6caa | |||
| e1cb96c484 | |||
| 9076c70d47 | |||
| 7e6dbc24f6 | |||
| e2feed494b | |||
| 4e933b4765 | |||
| 6e30851328 | |||
| 96b418cc8a | |||
| c1f3da082c | |||
| 6f5a7f65ac | |||
| 4f45ad549e | |||
| 6051ea8ae3 | |||
| 838855b1aa | |||
| 11bc9d0aeb | |||
| 05047d3a26 | |||
| 799c6a63ec | |||
| 50dfa037d0 | |||
| e2c6e637a4 | |||
| 444b3720bc | |||
| 17cc63ef63 | |||
| a5f9b29292 | |||
| 91881ff036 | |||
| e670f4e5c6 | |||
| 961f42bd43 | |||
| ab15ed2a05 | |||
| feb9d261ac | |||
| 76bb966b1a | |||
| 8da9e5466a | |||
| abff789b0f | |||
| 5d06bcec70 | |||
| 5f2106046c | |||
| 5ee89a3021 | |||
| bac9f43b66 | |||
| c9044151f5 | |||
| 070c5c3d33 | |||
| ea0825c0a6 | |||
| 2dfd69bbb3 | |||
| 8b35c3ff74 | |||
| 26271fc30c | |||
| 1865361163 | |||
| a5c3143512 | |||
| 6265bc1df7 | |||
| 547646de6d | |||
| f7fc2cbc3b | |||
| cdd65a70af | |||
| 24d40fa3e0 | |||
| bd87ff7f92 | |||
| 6b0d88721c | |||
| 5068eb2e01 | |||
| 9d928db3a8 | |||
| 37c9b26ff8 | |||
| 9ed911075e | |||
| 54805bc212 | |||
| d2e5ec6736 | |||
| 2983e3ca31 | |||
| 2afd9bc371 | |||
| cf6cf18f1a | |||
| 4342497305 | |||
| 1fa4d9169f | |||
| f37d030860 | |||
| f3a08447fd | |||
| a30cf3058e | |||
| 27ab9332c1 | |||
| 5d3484c74a | |||
| 24030a3f61 | |||
| b228a06e07 | |||
| 38a8ace5bb | |||
| ee2022e54c | |||
| a0ccd65d51 | |||
| 675b650290 | |||
| 5661d3826c | |||
| 11b3fe2289 | |||
| a2d40f3f16 | |||
| 0de307bb65 | |||
| 26f1e05ffc | |||
| 3948727b13 | |||
| de280b01fe | |||
| abb8a93e2f | |||
| d0556e61f9 | |||
| b9c8f47b01 | |||
| 3bed6cfc7c | |||
| 640d8cb67f | |||
| 6a5a3c97ed | |||
| ff26dfdd28 | |||
| 240819f955 | |||
| 8d1e55d101 | |||
| 6aabb5f17e | |||
| 15d7d6d7ab | |||
| 2c8f670d5f | |||
| 1c83e8653a | |||
| ef13dbfcdd | |||
| 1f49f994e6 | |||
| 3b14e974f8 | |||
| 12fe9174f0 | |||
| 82ea9ece5c | |||
| f0d21510f5 | |||
| 5e00113c65 | |||
| 48909886a2 | |||
| 73d8f069fe | |||
| 0657136605 | |||
| 85921808b3 | |||
| 7f5d6ea3f9 | |||
| 4e5e700213 | |||
| 0a12f28b58 | |||
| 2e4f38f6af | |||
| e3017c30bb | |||
| d032c20a54 | |||
| b4d6e27fb3 | |||
| 9a39f39b6f | |||
| ee5b7fdab8 | |||
| 710fdc73f1 | |||
| f9e8eb59e1 | |||
| bc3064cbb7 | |||
| a884cde18c | |||
| b1460742c3 | |||
| 2faf008c2e | |||
| 11fb12b920 | |||
| bfba53f958 | |||
| cb682cd8b7 | |||
| aa2fadd8da | |||
| 260bbe319d | |||
| 234272eb8f | |||
| 67abeb4722 | |||
| 63d300ac86 | |||
| 1d47fc6e2d | |||
| 994efe45fd | |||
| 6183683041 | |||
| 74c679eb2f | |||
| 479d073f1b | |||
| ff92f5af57 | |||
| 2a3ca619f9 | |||
| 23546b1234 | |||
| 078d2fe0e2 | |||
| 105e176a80 | |||
| 61a3d04e91 | |||
| e2f85fc1d0 | |||
| b6970d3504 | |||
| 8a3b4c69c8 | |||
| 9eb58b9596 | |||
| 1c04dcbe17 | |||
| 0b6bd46863 | |||
| f199d5187b | |||
| 569fbc9f39 |
@@ -1,28 +1,51 @@
|
||||
= How to contribute to the reference
|
||||
|
||||
The Spring Framework reference now uses http://asciidoctor.org/[asciidoctor]. This document describes how to contribute documentation updates.
|
||||
The Spring Framework reference now uses http://asciidoctor.org/[asciidoctor]. This
|
||||
document describes how to contribute documentation updates.
|
||||
|
||||
== Building with Gradle
|
||||
|
||||
You can build the documentation using gradle using the `asciidoc` task. For example, from the project root execute the following command:
|
||||
You can build the documentation using gradle using the `reference` task. For example, from
|
||||
the project root execute the following command:
|
||||
|
||||
gradlew asciidoc
|
||||
./gradlew reference
|
||||
|
||||
the output will be available at `spring-framework/build/asciidoc/index.html`
|
||||
the output will be available at `spring-framework/build/reference/htmlsingle/index.html`
|
||||
|
||||
== Live editing
|
||||
|
||||
One of the nice features about using asciidoctor is the support for live editing.
|
||||
|
||||
You will find a Guardfile already present at `spring-framework/src/asciidoc/Guardfile`. Then ensure to follow the setup instructions within the http://asciidoctor.org/docs/editing-asciidoc-with-live-preview/[Editing AsciiDoc with Live Preview] document.
|
||||
You will find a Guardfile already present at `spring-framework/src/asciidoc/Guardfile`.
|
||||
Make sure first to follow the setup instructions within the
|
||||
http://asciidoctor.org/docs/editing-asciidoc-with-live-preview/[Editing AsciiDoc with Live Preview]
|
||||
document. Once you have done that, there are additional gems to install to make it work
|
||||
(assuming that you are using http://livereload.com/[LiveReload]):
|
||||
|
||||
When running `guard start` within the `src/asciidoc/` folder, any changes to the `src/asciidoc/index.adoc` file will automatically be written at `src/asciidoc/build/index.html`.
|
||||
gem install guard-rspec guard-livereload
|
||||
|
||||
When running `guard start` within the `src/asciidoc/` folder, any changes to the
|
||||
`src/asciidoc/index.adoc` file will automatically be written at
|
||||
`src/asciidoc/build/index.html`.
|
||||
|
||||
== Troubleshooting
|
||||
|
||||
* If you are using LiveReload, make sure to select _Allow access to file URLs_ in the
|
||||
LiveEdit plugin options of your browser.
|
||||
* The icon used to enable _LiveReload_ can be a bit confusing. The dot is empty when it is
|
||||
disabled and full when the plugin is active. Make sure to enable it on the tab
|
||||
displaying the `index.html` file.
|
||||
* Ensure you are _not_ running guard start at all as two instances could not run at the
|
||||
same time. To exit a current session in a clean way, just type e in the shell.
|
||||
|
||||
== Documentation notes
|
||||
|
||||
Some notes on documentation
|
||||
|
||||
* It is important to keep whitespaces to a minimum to make it simple to edit files. This means use an editor with line wrapping rather than manually inserting hard returns.
|
||||
* Documentation is wrapped at 90 chars, ensure that you manually wrap your edits
|
||||
* Tabs are used for indentation, do not use spaces
|
||||
* Follow the existing style when inserting `source` blocks
|
||||
* http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/[Asciidoctor Quick Reference]
|
||||
* http://asciidoctor.org/docs/user-manual/[Asciidoctor Manual]
|
||||
* http://asciidoctor.org/docs/asciidoc-writers-guide/[Asciidoctor Writers Guide]
|
||||
|
||||
|
||||
+206
-175
@@ -13,13 +13,21 @@ configure(allprojects) { project ->
|
||||
group = "org.springframework"
|
||||
version = qualifyVersionIfNecessary(version)
|
||||
|
||||
ext.aspectjVersion = "1.8.0.M1"
|
||||
ext.groovyVersion = "1.8.9"
|
||||
ext.hsqldbVersion = "2.3.1"
|
||||
ext.junitVersion = "4.11"
|
||||
ext.slf4jVersion = "1.6.1"
|
||||
ext.jettyVersion = "9.1.0.v20131115"
|
||||
ext.gradleScriptDir = "${rootProject.projectDir}/gradle"
|
||||
ext.aspectjVersion = "1.7.4"
|
||||
ext.groovyVersion = "1.8.9"
|
||||
ext.hibernate3Version = "3.6.10.Final"
|
||||
ext.hibernate4Version = "4.2.8.Final"
|
||||
ext.hibValVersion = "4.3.1.Final"
|
||||
ext.hsqldbVersion = "2.3.1"
|
||||
ext.jackson1Version = "1.9.13"
|
||||
ext.jackson2Version = "2.3.1"
|
||||
ext.jettyVersion = "9.1.2.v20140210"
|
||||
ext.jodaVersion = "2.3"
|
||||
ext.junitVersion = "4.11"
|
||||
ext.slf4jVersion = "1.7.5"
|
||||
ext.xstreamVersion = "1.4.6"
|
||||
|
||||
ext.gradleScriptDir = "${rootProject.projectDir}/gradle"
|
||||
|
||||
apply plugin: "propdeps"
|
||||
apply plugin: "java"
|
||||
@@ -57,16 +65,13 @@ configure(allprojects) { project ->
|
||||
systemProperty("java.awt.headless", "true")
|
||||
systemProperty("testGroups", project.properties.get("testGroups"))
|
||||
scanForTestClasses = false
|
||||
include '**/*Tests.*'
|
||||
exclude '**/*Abstract*.*'
|
||||
include(["**/*Tests.*", "**/*Test.*"])
|
||||
exclude "**/Abstract*.*"
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url "http://repo.spring.io/libs-release" }
|
||||
maven { url "http://repo.spring.io/milestone" } // for AspectJ 1.8.0.M1
|
||||
maven { url "https://repository.apache.org/content/repositories/releases" } // tomcat 8
|
||||
// maven { url "https://repository.apache.org/content/repositories/snapshots" } // tomcat 8 snapshots
|
||||
maven { url "https://maven.java.net/content/repositories/releases" } // javax.websocket, tyrus
|
||||
maven { url "https://oss.sonatype.org/content/repositories/releases" } // javax.cache
|
||||
}
|
||||
|
||||
@@ -94,7 +99,8 @@ configure(allprojects) { project ->
|
||||
"http://ehcache.org/apidocs/",
|
||||
"http://quartz-scheduler.org/api/2.1.7/",
|
||||
"http://jackson.codehaus.org/1.9.4/javadoc/",
|
||||
"http://fasterxml.github.com/jackson-core/javadoc/2.2.0/",
|
||||
"http://fasterxml.github.com/jackson-core/javadoc/2.3.0/",
|
||||
"http://fasterxml.github.com/jackson-databind/javadoc/2.3.0/",
|
||||
"http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs"
|
||||
] as String[]
|
||||
}
|
||||
@@ -164,12 +170,12 @@ project("spring-build-src") {
|
||||
project("spring-core") {
|
||||
description = "Spring Core"
|
||||
|
||||
// As of Spring 4.0, spring-core includes asm 4.2 and repackages cglib 3.0, inlining
|
||||
// both into the spring-core jar. cglib 3.0 itself depends on asm 4, and is therefore
|
||||
// As of Spring 4.0, spring-core includes asm 4.2 and repackages cglib 3.1, inlining
|
||||
// both into the spring-core jar. cglib 3.1 itself depends on asm 4, 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.0"
|
||||
def objenesisVersion = "2.0"
|
||||
def cglibVersion = "3.1"
|
||||
def objenesisVersion = "2.1"
|
||||
|
||||
configurations {
|
||||
jarjar
|
||||
@@ -225,9 +231,9 @@ project("spring-core") {
|
||||
jarjar("com.googlecode.jarjar:jarjar:1.3")
|
||||
|
||||
compile(files(cglibRepackJar))
|
||||
compile("commons-logging:commons-logging:1.1.1")
|
||||
compile("commons-logging:commons-logging:1.1.3")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("net.sf.jopt-simple:jopt-simple:4.4")
|
||||
optional("net.sf.jopt-simple:jopt-simple:4.6")
|
||||
optional("log4j:log4j:1.2.17")
|
||||
testCompile("xmlunit:xmlunit:1.3")
|
||||
testCompile("org.codehaus.woodstox:wstx-asl:3.2.7") {
|
||||
@@ -261,14 +267,14 @@ project("spring-beans") {
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
provided("javax.el:javax.el-api:2.2.4")
|
||||
provided("javax.inject:javax.inject:1")
|
||||
optional("javax.el:javax.el-api:2.2.4")
|
||||
optional("javax.inject:javax.inject:1")
|
||||
testCompile("log4j:log4j:1.2.17")
|
||||
}
|
||||
}
|
||||
|
||||
project('spring-beans-groovy') {
|
||||
description 'Groovy Bean Definitions'
|
||||
project("spring-beans-groovy") {
|
||||
description "Groovy Bean Definitions"
|
||||
merge.into = project(":spring-beans")
|
||||
apply plugin: "groovy"
|
||||
|
||||
@@ -282,7 +288,7 @@ project('spring-beans-groovy') {
|
||||
sourceSets {
|
||||
main {
|
||||
groovy {
|
||||
srcDir 'src/main/java'
|
||||
srcDir "src/main/java"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -297,14 +303,14 @@ project("spring-aop") {
|
||||
description = "Spring AOP"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
compile(files(project(":spring-core").objenesisRepackJar))
|
||||
compile(project(":spring-beans"))
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
optional("com.jamonapi:jamon:2.4")
|
||||
optional("commons-pool:commons-pool:1.5.3")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("commons-pool:commons-pool:1.6")
|
||||
optional("com.jamonapi:jamon:2.4")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,28 +349,26 @@ project("spring-context") {
|
||||
apply plugin: "groovy"
|
||||
|
||||
dependencies {
|
||||
optional(project(":spring-instrument"))
|
||||
compile(project(":spring-aop"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-expression"))
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
optional("javax.ejb:ejb-api:3.0")
|
||||
optional(project(":spring-instrument"))
|
||||
optional("javax.inject:javax.inject:1")
|
||||
optional("javax.ejb:ejb-api:3.0")
|
||||
optional("javax.enterprise.concurrent:javax.enterprise.concurrent-api:1.0")
|
||||
optional("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1")
|
||||
optional("org.eclipse.persistence:javax.persistence:2.0.0")
|
||||
optional("joda-time:joda-time:2.2")
|
||||
optional("org.beanshell:bsh:2.0b4")
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("org.jruby:jruby:1.7.2")
|
||||
optional("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
optional("javax.validation:validation-api:1.0.0.GA")
|
||||
optional("org.hibernate:hibernate-validator:4.3.0.Final")
|
||||
optional("org.hibernate:hibernate-validator:${hibValVersion}")
|
||||
optional("joda-time:joda-time:${jodaVersion}")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.2.2")
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("org.beanshell:bsh:2.0b4")
|
||||
optional("org.jruby:jruby:1.7.10")
|
||||
testCompile("javax.inject:javax.inject-tck:1")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.4")
|
||||
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
}
|
||||
|
||||
// pick up RmiInvocationWrapperRTD.xml in src/main
|
||||
@@ -382,19 +386,18 @@ project("spring-messaging") {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-context"))
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.2.2")
|
||||
optional("org.projectreactor:reactor-core:1.0.0.RELEASE")
|
||||
optional("org.projectreactor:reactor-tcp:1.0.0.RELEASE")
|
||||
optional("org.eclipse.jetty.websocket:websocket-server:${jettyVersion}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet-api"
|
||||
}
|
||||
optional("org.eclipse.jetty.websocket:websocket-client:${jettyVersion}")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
testCompile(project(":spring-test"))
|
||||
testCompile("com.thoughtworks.xstream:xstream:1.4.4")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.2.2")
|
||||
testCompile("javax.inject:javax.inject-tck:1")
|
||||
testCompile("javax.servlet:javax.servlet-api:3.1.0")
|
||||
testCompile("log4j:log4j:1.2.17")
|
||||
testCompile("javax.validation:validation-api:1.0.0.GA")
|
||||
testCompile("com.thoughtworks.xstream:xstream:${xstreamVersion}")
|
||||
testCompile("org.apache.activemq:activemq-broker:5.8.0")
|
||||
testCompile("org.apache.activemq:activemq-kahadb-store:5.8.0") {
|
||||
exclude group: "org.springframework", module: "spring-context"
|
||||
@@ -403,8 +406,11 @@ project("spring-messaging") {
|
||||
testCompile("org.eclipse.jetty:jetty-webapp:${jettyVersion}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet-api"
|
||||
}
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:8.0.0-RC5")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:8.0.0-RC5")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:8.0.3")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:8.0.3")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:8.0.3")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.4")
|
||||
testCompile("log4j:log4j:1.2.17")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
}
|
||||
@@ -413,17 +419,17 @@ project("spring-tx") {
|
||||
description = "Spring Transaction"
|
||||
|
||||
dependencies {
|
||||
optional(project(":spring-context")) // for JCA, @EnableTransactionManagement
|
||||
optional(project(":spring-aop"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
provided("com.ibm.websphere:uow:6.0.2.17")
|
||||
optional("javax.resource:connector-api:1.5")
|
||||
optional(project(":spring-aop"))
|
||||
optional(project(":spring-context")) // for JCA, @EnableTransactionManagement
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("javax.transaction:javax.transaction-api:1.2")
|
||||
optional("javax.resource:connector-api:1.5")
|
||||
optional("javax.ejb:ejb-api:3.0")
|
||||
testCompile("org.eclipse.persistence:javax.persistence:2.0.0")
|
||||
optional("com.ibm.websphere:uow:6.0.2.17")
|
||||
testCompile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
testCompile("org.eclipse.persistence:javax.persistence:2.0.0")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,11 +452,11 @@ project("spring-oxm") {
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
testCompile(project(":spring-context"))
|
||||
optional("com.thoughtworks.xstream:xstream:1.4.4")
|
||||
optional("com.thoughtworks.xstream:xstream:${xstreamVersion}")
|
||||
optional("org.jibx:jibx-run:1.2.5")
|
||||
optional("org.apache.xmlbeans:xmlbeans:2.6.0")
|
||||
optional("org.codehaus.castor:castor-xml:1.3.2")
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile("org.codehaus.jettison:jettison:1.0.1")
|
||||
testCompile("xmlunit:xmlunit:1.3")
|
||||
testCompile("xmlpull:xmlpull:1.1.3.4a")
|
||||
@@ -469,13 +475,13 @@ project("spring-jms") {
|
||||
compile(project(":spring-aop"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-tx"))
|
||||
optional(project(":spring-oxm"))
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
provided("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1")
|
||||
optional(project(":spring-oxm"))
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
optional("javax.resource:connector-api:1.5")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.9.12")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.2.2")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:${jackson1Version}")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,16 +489,16 @@ project("spring-jdbc") {
|
||||
description = "Spring JDBC"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
optional(project(":spring-context")) // for JndiDataSourceLookup
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-tx"))
|
||||
optional(project(":spring-context")) // for JndiDataSourceLookup
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
optional("c3p0:c3p0:0.9.1.2")
|
||||
optional("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
optional("com.h2database:h2:1.0.71")
|
||||
optional("org.apache.derby:derby:10.5.3.0_1")
|
||||
optional("org.apache.derby:derbyclient:10.5.3.0_1")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
optional("org.apache.derby:derby:10.10.1.1")
|
||||
optional("org.apache.derby:derbyclient:10.10.1.1")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,23 +512,22 @@ project("spring-context-support") {
|
||||
optional(project(":spring-jdbc")) // for Quartz support
|
||||
optional(project(":spring-tx")) // for Quartz support
|
||||
optional("javax.mail:mail:1.4.7")
|
||||
optional("javax.cache:cache-api:1.0.0-PFD")
|
||||
optional("com.google.guava:guava:14.0.1")
|
||||
optional("javax.cache:cache-api:1.0.0-RC1")
|
||||
optional("com.google.guava:guava:16.0.1")
|
||||
optional("net.sf.ehcache:ehcache-core:2.6.5")
|
||||
optional("org.quartz-scheduler:quartz:1.8.6") {
|
||||
exclude group: "org.slf4j", module: "slf4j-log4j12"
|
||||
}
|
||||
optional("org.codehaus.fabric3.api:commonj:1.1.0")
|
||||
optional("org.apache.velocity:velocity:1.7")
|
||||
optional("org.freemarker:freemarker:2.3.19")
|
||||
optional("org.freemarker:freemarker:2.3.20")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("net.sf.jasperreports:jasperreports:5.1.0")
|
||||
optional("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
provided("javax.activation:activation:1.1")
|
||||
optional("net.sf.jasperreports:jasperreports:5.5.1")
|
||||
testCompile("org.apache.poi:poi:3.9")
|
||||
testCompile("commons-beanutils:commons-beanutils:1.8.0") // for Velocity/JasperReports
|
||||
testCompile("commons-digester:commons-digester:1.8.1") // for Velocity/JasperReports
|
||||
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
}
|
||||
|
||||
// pick up **/*.types files in src/main
|
||||
@@ -533,25 +538,24 @@ project("spring-web") {
|
||||
description = "Spring Web"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans")) // for MultiPartFilter
|
||||
compile(project(":spring-aop")) // for JaxWsPortProxyFactoryBean
|
||||
compile(project(":spring-beans")) // for MultiPartFilter
|
||||
compile(project(":spring-context"))
|
||||
optional(project(":spring-oxm")) // for MarshallingHttpMessageConverter
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
provided("javax.el:javax.el-api:2.2.4")
|
||||
provided("javax.faces:javax.faces-api:2.2")
|
||||
provided("javax.portlet:portlet-api:2.0")
|
||||
compile(project(":spring-core"))
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
provided("javax.servlet.jsp:jsp-api:2.1")
|
||||
provided("javax.activation:activation:1.1")
|
||||
optional(project(":spring-oxm")) // for MarshallingHttpMessageConverter
|
||||
optional("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.portlet:portlet-api:2.0")
|
||||
optional("javax.el:javax.el-api:2.2.4")
|
||||
optional("javax.faces:javax.faces-api:2.2")
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("com.caucho:hessian:4.0.7")
|
||||
optional("rome:rome:1.0")
|
||||
optional("commons-fileupload:commons-fileupload:1.3")
|
||||
optional("org.apache.httpcomponents:httpclient:4.3.1")
|
||||
optional("commons-fileupload:commons-fileupload:1.3.1")
|
||||
optional("org.apache.httpcomponents:httpclient:4.3.2")
|
||||
optional("org.apache.httpcomponents:httpasyncclient:4.0")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.9.12")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.2.2")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:${jackson1Version}")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
optional("rome:rome:1.0")
|
||||
optional("taglibs:standard:1.1.2")
|
||||
optional("org.eclipse.jetty:jetty-servlet:${jettyVersion}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet-api"
|
||||
@@ -563,7 +567,6 @@ project("spring-web") {
|
||||
testCompile(project(":spring-context-support")) // for JafMediaTypeFactory
|
||||
testCompile("xmlunit:xmlunit:1.3")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("log4j:log4j:1.2.17")
|
||||
}
|
||||
|
||||
// pick up ContextLoader.properties in src/main
|
||||
@@ -581,7 +584,7 @@ project("spring-websocket") {
|
||||
optional(project(":spring-webmvc"))
|
||||
optional("javax.servlet:javax.servlet-api:3.1.0")
|
||||
optional("javax.websocket:javax.websocket-api:1.0")
|
||||
optional("org.apache.tomcat:tomcat-websocket:8.0.0-RC5") {
|
||||
optional("org.apache.tomcat:tomcat-websocket:8.0.3") {
|
||||
exclude group: "org.apache.tomcat", module: "tomcat-websocket-api"
|
||||
exclude group: "org.apache.tomcat", module: "tomcat-servlet-api"
|
||||
}
|
||||
@@ -594,13 +597,21 @@ project("spring-websocket") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet"
|
||||
}
|
||||
optional("org.eclipse.jetty.websocket:websocket-client:${jettyVersion}")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.2.2")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.9.12")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:8.0.0-RC5")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("log4j:log4j:1.2.17")
|
||||
optional("io.undertow:undertow-core:1.0.0.Final")
|
||||
optional("io.undertow:undertow-servlet:1.0.0.Final") {
|
||||
exclude group: "org.jboss.spec.javax.servlet", module: "jboss-servlet-api_3.1_spec"
|
||||
}
|
||||
optional("io.undertow:undertow-websockets-jsr:1.0.0.Final") {
|
||||
exclude group: "org.jboss.spec.javax.websocket", module: "jboss-websocket-api_1.0_spec"
|
||||
}
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:8.0.3")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:8.0.3")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:8.0.3")
|
||||
testCompile("org.projectreactor:reactor-core:1.0.0.RELEASE")
|
||||
testCompile("org.projectreactor:reactor-tcp:1.0.0.RELEASE")
|
||||
testCompile("log4j:log4j:1.2.17")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,25 +619,25 @@ project("spring-orm") {
|
||||
description = "Spring Object/Relational Mapping"
|
||||
|
||||
dependencies {
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-jdbc"))
|
||||
compile(project(":spring-tx"))
|
||||
optional(project(":spring-aop"))
|
||||
optional(project(":spring-context"))
|
||||
optional(project(":spring-web"))
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("org.eclipse.persistence:javax.persistence:2.0.0")
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.core:2.4.0")
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.jpa:2.4.0")
|
||||
optional("org.hibernate:hibernate-core:3.6.9.Final")
|
||||
optional("org.hibernate:hibernate-entitymanager:3.6.9.Final")
|
||||
optional("org.hibernate:hibernate-core:${hibernate3Version}")
|
||||
optional("org.hibernate:hibernate-entitymanager:${hibernate3Version}")
|
||||
optional("org.apache.openjpa:openjpa:2.2.1")
|
||||
optional("javax.jdo:jdo-api:3.0")
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.2.2")
|
||||
optional("javax.servlet:javax.servlet-api:3.0.1")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.4")
|
||||
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
optional(project(":spring-aop"))
|
||||
optional(project(":spring-context"))
|
||||
compile(project(":spring-tx"))
|
||||
compile(project(":spring-jdbc"))
|
||||
optional(project(":spring-web"))
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,11 +646,11 @@ project("spring-orm-hibernate4") {
|
||||
merge.into = project(":spring-orm")
|
||||
|
||||
dependencies {
|
||||
provided(project(":spring-tx"))
|
||||
provided(project(":spring-jdbc"))
|
||||
optional("org.hibernate:hibernate-core:4.2.2.Final")
|
||||
optional("org.hibernate:hibernate-entitymanager:4.2.2.Final")
|
||||
provided(project(":spring-tx"))
|
||||
optional(project(":spring-web"))
|
||||
optional("org.hibernate:hibernate-core:${hibernate4Version}")
|
||||
optional("org.hibernate:hibernate-entitymanager:${hibernate4Version}")
|
||||
optional("javax.servlet:javax.servlet-api:3.0.1")
|
||||
}
|
||||
}
|
||||
@@ -648,35 +659,47 @@ project("spring-webmvc") {
|
||||
description = "Spring Web MVC"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").objenesisRepackJar))
|
||||
compile(project(":spring-expression"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-web"))
|
||||
compile(project(":spring-context"))
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional(project(":spring-context-support")) // for Velocity support
|
||||
optional(project(":spring-oxm")) // for MarshallingView
|
||||
optional("org.apache.tiles:tiles-api:2.1.2")
|
||||
optional("org.apache.tiles:tiles-core:2.1.2")
|
||||
optional("org.apache.tiles:tiles-jsp:2.1.2")
|
||||
optional("org.apache.tiles:tiles-servlet:2.1.2")
|
||||
optional("net.sourceforge.jexcelapi:jxl:2.6.3")
|
||||
optional("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.servlet:jstl:1.2")
|
||||
optional("net.sourceforge.jexcelapi:jxl:2.6.12")
|
||||
optional("org.apache.poi:poi:3.9")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("net.sf.jasperreports:jasperreports:5.1.0") {
|
||||
exclude group: "xml-apis", module: "xml-apis"
|
||||
}
|
||||
optional("rome:rome:1.0")
|
||||
optional("org.apache.velocity:velocity:1.7")
|
||||
optional("velocity-tools:velocity-tools-view:1.4")
|
||||
optional("org.freemarker:freemarker:2.3.19")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.9.12")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.2.2")
|
||||
provided("javax.servlet:jstl:1.2")
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
provided("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("org.freemarker:freemarker:2.3.20")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("net.sf.jasperreports:jasperreports:5.5.0") {
|
||||
exclude group: "xml-apis", module: "xml-apis"
|
||||
}
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:${jackson1Version}")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
optional("rome:rome:1.0")
|
||||
optional("org.apache.tiles:tiles-api:2.2.2")
|
||||
optional("org.apache.tiles:tiles-core:2.2.2") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-servlet:2.2.2") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-jsp:2.2.2") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-el:2.2.2") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-extras:2.2.2") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
exclude group: "org.springframework", module: "spring-web"
|
||||
}
|
||||
testCompile(project(":spring-aop"))
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("rhino:js:1.7R1")
|
||||
testCompile("xmlunit:xmlunit:1.3")
|
||||
testCompile("dom4j:dom4j:1.6.1") {
|
||||
@@ -694,11 +717,12 @@ project("spring-webmvc") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet"
|
||||
}
|
||||
testCompile("javax.validation:validation-api:1.0.0.GA")
|
||||
testCompile("commons-fileupload:commons-fileupload:1.2")
|
||||
testCompile("org.hibernate:hibernate-validator:${hibValVersion}")
|
||||
testCompile("org.apache.httpcomponents:httpclient:4.3.2")
|
||||
testCompile("commons-fileupload:commons-fileupload:1.3.1")
|
||||
testCompile("commons-io:commons-io:1.3")
|
||||
testCompile("org.hibernate:hibernate-validator:4.3.0.Final")
|
||||
testCompile("org.apache.httpcomponents:httpclient:4.3.1")
|
||||
testCompile("joda-time:joda-time:2.2")
|
||||
testCompile("joda-time:joda-time:${jodaVersion}")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
|
||||
// pick up DispatcherServlet.properties in src/main
|
||||
@@ -712,9 +736,10 @@ project("spring-webmvc-tiles3") {
|
||||
dependencies {
|
||||
provided(project(":spring-context"))
|
||||
provided(project(":spring-web"))
|
||||
provided("javax.el:javax.el-api:2.2.4")
|
||||
provided("javax.servlet:jstl:1.2")
|
||||
provided("javax.servlet.jsp:jsp-api:2.1")
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.servlet:jstl:1.2")
|
||||
optional("javax.el:javax.el-api:2.2.4")
|
||||
optional("org.apache.tiles:tiles-request-api:1.0.1")
|
||||
optional("org.apache.tiles:tiles-api:3.0.1")
|
||||
optional("org.apache.tiles:tiles-core:3.0.1") {
|
||||
@@ -726,14 +751,13 @@ project("spring-webmvc-tiles3") {
|
||||
optional("org.apache.tiles:tiles-jsp:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-el:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-extras:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
exclude group: "org.springframework", module: "spring-web"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-el:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
}
|
||||
@@ -742,14 +766,14 @@ project("spring-webmvc-portlet") {
|
||||
description = "Spring Web Portlet"
|
||||
|
||||
dependencies {
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
provided("javax.portlet:portlet-api:2.0")
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-web"))
|
||||
compile(project(":spring-webmvc"))
|
||||
optional("commons-fileupload:commons-fileupload:1.2")
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
provided("javax.portlet:portlet-api:2.0")
|
||||
optional("commons-fileupload:commons-fileupload:1.3.1")
|
||||
}
|
||||
|
||||
// pick up DispatcherPortlet.properties in src/main
|
||||
@@ -770,31 +794,29 @@ project("spring-test") {
|
||||
optional(project(":spring-webmvc"))
|
||||
optional(project(":spring-webmvc-portlet"))
|
||||
optional("junit:junit:${junitVersion}")
|
||||
optional("org.testng:testng:6.8.5")
|
||||
optional("org.testng:testng:6.8.7")
|
||||
optional("javax.inject:javax.inject:1")
|
||||
optional("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.servlet:jstl:1.2")
|
||||
optional("javax.portlet:portlet-api:2.0")
|
||||
optional("org.eclipse.persistence:javax.persistence:2.0.0")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
provided("javax.inject:javax.inject:1")
|
||||
provided("javax.activation:activation:1.1")
|
||||
provided("javax.servlet:jstl:1.2")
|
||||
optional("org.hamcrest:hamcrest-core:1.3")
|
||||
optional("com.jayway.jsonpath:json-path:0.9.0")
|
||||
optional("xmlunit:xmlunit:1.3")
|
||||
testCompile(project(":spring-context-support"))
|
||||
testCompile(project(":spring-oxm"))
|
||||
testCompile(project(":spring-webmvc-tiles3"))
|
||||
testCompile("org.hibernate:hibernate-core:3.6.9.Final")
|
||||
testCompile "org.slf4j:slf4j-jcl:${slf4jVersion}"
|
||||
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
testCompile("org.hibernate:hibernate-validator:4.3.0.Final")
|
||||
testCompile("org.codehaus.jackson:jackson-mapper-asl:1.9.12")
|
||||
testCompile("com.fasterxml.jackson.core:jackson-databind:2.2.2")
|
||||
testCompile("com.thoughtworks.xstream:xstream:1.4.4")
|
||||
testCompile("rome:rome:1.0")
|
||||
testCompile("javax.activation:activation:1.1")
|
||||
testCompile("javax.mail:mail:1.4.7")
|
||||
testCompile("javax.ejb:ejb-api:3.0")
|
||||
testCompile("org.hibernate:hibernate-core:${hibernate3Version}")
|
||||
testCompile("org.hibernate:hibernate-entitymanager:${hibernate3Version}")
|
||||
testCompile("org.hibernate:hibernate-validator:${hibValVersion}")
|
||||
testCompile("com.thoughtworks.xstream:xstream:${xstreamVersion}")
|
||||
testCompile("org.codehaus.jackson:jackson-mapper-asl:${jackson1Version}")
|
||||
testCompile("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
testCompile("rome:rome:1.0")
|
||||
testCompile("org.apache.tiles:tiles-request-api:1.0.1")
|
||||
testCompile("org.apache.tiles:tiles-api:3.0.1")
|
||||
testCompile("org.apache.tiles:tiles-core:3.0.1") {
|
||||
@@ -803,25 +825,35 @@ project("spring-test") {
|
||||
testCompile("org.apache.tiles:tiles-servlet:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
testCompile "org.slf4j:slf4j-jcl:${slf4jVersion}"
|
||||
}
|
||||
|
||||
task testNG(type: Test) {
|
||||
useTestNG()
|
||||
// forkEvery 1
|
||||
scanForTestClasses = false
|
||||
include "**/testng/*.*"
|
||||
exclude "**/FailingBeforeAndAfterMethodsTests.class"
|
||||
include(["**/testng/**/*Tests.*", "**/testng/**/*Test.*"])
|
||||
// "TestCase" classes are run by other test classes, not the build.
|
||||
exclude "**/*TestCase.class"
|
||||
exclude(["**/Abstract*.*", "**/*TestCase.class", "**/FailingBeforeAndAfterMethodsTests.class"])
|
||||
// Generate TestNG reports alongside JUnit reports.
|
||||
getReports().getHtml().setEnabled(true)
|
||||
// show standard out and standard error of the test JVM(s) on the console
|
||||
// testLogging.showStandardStreams = true
|
||||
}
|
||||
|
||||
test {
|
||||
dependsOn testNG
|
||||
useJUnit()
|
||||
exclude "**/testng/*.*"
|
||||
include(["**/*Tests.*", "**/*Test.*"])
|
||||
// In general, we exclude all classes under the 'testng' package.
|
||||
// "TestCase" classes are run by other test classes, not the build.
|
||||
exclude(["**/*TestCase.class", "**/*TestSuite.class"])
|
||||
// "TestSuite" classes only exist as a convenience to the develper; they
|
||||
// should not be run by the build.
|
||||
exclude(["**/testng/**/*.*", "**/Abstract*.*", "**/*TestCase.class", "**/*TestSuite.class"])
|
||||
// FailingBeforeAndAfterMethodsTests is actually a JUnit-based test which
|
||||
// itself runs TestNG manually in order to test our TestNG support.
|
||||
include "**/testng/FailingBeforeAndAfterMethodsTests"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -830,21 +862,20 @@ project("spring-aspects") {
|
||||
apply from: "aspects.gradle"
|
||||
|
||||
dependencies {
|
||||
optional(project(":spring-beans")) // for @Configurable support
|
||||
optional(project(":spring-aop")) // for @Async support
|
||||
optional(project(":spring-context")) // for @Enable* support
|
||||
compile(project(":spring-context-support")) // for JavaMail support
|
||||
optional(project(":spring-tx")) // for JPA, @Transactional support
|
||||
optional(project(":spring-orm")) // for JPA exception translation support
|
||||
aspects(project(":spring-orm"))
|
||||
ajc("org.aspectj:aspectjtools:1.8.0.M1") // needed for ajc on JDK 8 only
|
||||
rt("org.aspectj:aspectjrt:1.8.0.M1") // needed for ajc on JDK 8 only
|
||||
compile("org.aspectj:aspectjweaver:${aspectjVersion}") // exposing regular AspectJ version to users
|
||||
provided("org.eclipse.persistence:javax.persistence:2.0.0")
|
||||
testCompile("javax.mail:mail:1.4.7")
|
||||
ajc("org.aspectj:aspectjtools:${aspectjVersion}")
|
||||
rt("org.aspectj:aspectjrt:${aspectjVersion}")
|
||||
compile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional(project(":spring-aop")) // for @Async support
|
||||
optional(project(":spring-beans")) // for @Configurable support
|
||||
optional(project(":spring-context")) // for @Enable* support
|
||||
optional(project(":spring-context-support")) // for JavaMail support
|
||||
optional(project(":spring-orm")) // for JPA exception translation support
|
||||
optional(project(":spring-tx")) // for JPA, @Transactional support
|
||||
testCompile(project(":spring-core")) // for CodeStyleAspect
|
||||
compile(project(":spring-beans")) // for "p" namespace visibility
|
||||
testCompile(project(":spring-test"))
|
||||
testCompile("javax.mail:mail:1.4.7")
|
||||
}
|
||||
|
||||
eclipse.project {
|
||||
@@ -933,23 +964,23 @@ configure(rootProject) {
|
||||
configurations.archives.artifacts.clear()
|
||||
|
||||
dependencies { // for integration tests
|
||||
testCompile(project(":spring-core"))
|
||||
testCompile(project(":spring-beans"))
|
||||
testCompile(project(":spring-aop"))
|
||||
testCompile(project(":spring-expression"))
|
||||
testCompile(project(":spring-beans"))
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile(project(":spring-tx"))
|
||||
testCompile(project(":spring-core"))
|
||||
testCompile(project(":spring-expression"))
|
||||
testCompile(project(":spring-jdbc"))
|
||||
testCompile(project(":spring-orm"))
|
||||
testCompile(project(":spring-test"))
|
||||
testCompile(project(":spring-tx"))
|
||||
testCompile(project(":spring-web"))
|
||||
testCompile(project(":spring-webmvc-portlet"))
|
||||
testCompile(project(":spring-orm"))
|
||||
testCompile("org.hibernate:hibernate-core:4.2.2.Final")
|
||||
testCompile("javax.servlet:javax.servlet-api:3.0.1")
|
||||
testCompile("javax.portlet:portlet-api:2.0")
|
||||
testCompile("javax.inject:javax.inject:1")
|
||||
testCompile("javax.resource:connector-api:1.5")
|
||||
testCompile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
testCompile("org.hibernate:hibernate-core:${hibernate4Version}")
|
||||
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
}
|
||||
|
||||
@@ -981,7 +1012,7 @@ 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" },
|
||||
@@ -1118,7 +1149,7 @@ configure(rootProject) {
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
description = "Generates gradlew[.bat] scripts"
|
||||
gradleVersion = "1.9"
|
||||
gradleVersion = "1.11"
|
||||
|
||||
doLast() {
|
||||
def gradleOpts = "-XX:MaxMetaspaceSize=1024m -Xmx1024m"
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
version=4.0.0.RELEASE
|
||||
version=4.0.2.RELEASE
|
||||
|
||||
@@ -22,10 +22,10 @@ def customizePom(pom, gradleProject) {
|
||||
generatedPom.project {
|
||||
name = gradleProject.description
|
||||
description = gradleProject.description
|
||||
url = "https://github.com/SpringSource/spring-framework"
|
||||
url = "https://github.com/spring-projects/spring-framework"
|
||||
organization {
|
||||
name = "SpringSource"
|
||||
url = "http://springsource.org/spring-framework"
|
||||
name = "Spring IO"
|
||||
url = "http://projects.spring.io/spring-framework"
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
@@ -35,9 +35,9 @@ def customizePom(pom, gradleProject) {
|
||||
}
|
||||
}
|
||||
scm {
|
||||
url = "https://github.com/SpringSource/spring-framework"
|
||||
connection = "scm:git:git://github.com/SpringSource/spring-framework"
|
||||
developerConnection = "scm:git:git://github.com/SpringSource/spring-framework"
|
||||
url = "https://github.com/spring-projects/spring-framework"
|
||||
connection = "scm:git:git://github.com/spring-projects/spring-framework"
|
||||
developerConnection = "scm:git:git://github.com/spring-projects/spring-framework"
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+2
-2
@@ -1,6 +1,6 @@
|
||||
#Wed Nov 20 13:14:38 PST 2013
|
||||
#Wed Feb 12 23:28:21 CET 2014
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.9-bin.zip
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-bin.zip
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -19,9 +19,9 @@ package org.springframework.aop;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* A specialized type of MethodMatcher that takes into account introductions when
|
||||
* matching methods. If there are no introductions on the target class, a method
|
||||
* matcher may be able to optimize matching more effectively for example.
|
||||
* A specialized type of {@link MethodMatcher} that takes into account introductions
|
||||
* when matching methods. If there are no introductions on the target class,
|
||||
* a method matcher may be able to optimize matching more effectively for example.
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
|
||||
+49
-54
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -42,6 +42,7 @@ import org.aspectj.weaver.tools.PointcutParameter;
|
||||
import org.aspectj.weaver.tools.PointcutParser;
|
||||
import org.aspectj.weaver.tools.PointcutPrimitive;
|
||||
import org.aspectj.weaver.tools.ShadowMatch;
|
||||
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.IntroductionAwareMethodMatcher;
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
@@ -55,6 +56,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -144,14 +146,14 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
/**
|
||||
* Set the parameter names for the pointcut.
|
||||
*/
|
||||
public void setParameterNames(String[] names) {
|
||||
public void setParameterNames(String... names) {
|
||||
this.pointcutParameterNames = names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parameter types for the pointcut.
|
||||
*/
|
||||
public void setParameterTypes(Class<?>[] types) {
|
||||
public void setParameterTypes(Class<?>... types) {
|
||||
this.pointcutParameterTypes = types;
|
||||
}
|
||||
|
||||
@@ -191,9 +193,9 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
private PointcutExpression buildPointcutExpression() {
|
||||
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ? ((ConfigurableBeanFactory) this.beanFactory)
|
||||
.getBeanClassLoader() : Thread.currentThread()
|
||||
.getContextClassLoader());
|
||||
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
return buildPointcutExpression(cl);
|
||||
}
|
||||
|
||||
@@ -205,8 +207,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
|
||||
for (int i = 0; i < pointcutParameters.length; i++) {
|
||||
pointcutParameters[i] = parser.createPointcutParameter(
|
||||
this.pointcutParameterNames[i],
|
||||
this.pointcutParameterTypes[i]);
|
||||
this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
|
||||
}
|
||||
return parser.parsePointcutExpression(
|
||||
replaceBooleanOperators(getExpression()),
|
||||
@@ -252,16 +253,15 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
checkReadyToMatch();
|
||||
try {
|
||||
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
|
||||
} catch (ReflectionWorldException e) {
|
||||
logger.debug("PointcutExpression matching rejected target class", e);
|
||||
}
|
||||
catch (ReflectionWorldException rwe) {
|
||||
logger.debug("PointcutExpression matching rejected target class", rwe);
|
||||
try {
|
||||
// Actually this is still a "maybe" - treat the pointcut as dynamic if we
|
||||
// don't know enough yet
|
||||
// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
|
||||
return getFallbackPointcutExpression(targetClass).couldMatchJoinPointsInType(targetClass);
|
||||
} catch (BCException ex) {
|
||||
logger.debug(
|
||||
"Fallback PointcutExpression matching rejected target class",
|
||||
ex);
|
||||
}
|
||||
catch (BCException bce) {
|
||||
logger.debug("Fallback PointcutExpression matching rejected target class", bce);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -288,7 +288,15 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
}
|
||||
else {
|
||||
// the maybe case
|
||||
return (beanHasIntroductions || matchesIgnoringSubtypes(shadowMatch) || matchesTarget(shadowMatch, targetClass));
|
||||
if (beanHasIntroductions) {
|
||||
return true;
|
||||
}
|
||||
// A match test returned maybe - if there are any subtype sensitive variables
|
||||
// involved in the test (this, target, at_this, at_target, at_annotation) then
|
||||
// we say this is not a match as in Spring there will never be a different
|
||||
// runtime subtype.
|
||||
RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
|
||||
return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,14 +352,13 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (joinPointMatch.matches() && pmi != null) {
|
||||
bindParameters(pmi, joinPointMatch);
|
||||
if (joinPointMatch.matches()) {
|
||||
bindParameters(pmi, joinPointMatch);
|
||||
}
|
||||
}
|
||||
return joinPointMatch.matches();
|
||||
}
|
||||
|
||||
|
||||
protected String getCurrentProxiedBeanName() {
|
||||
return ProxyCreationContext.getCurrentProxiedBeanName();
|
||||
}
|
||||
@@ -361,29 +368,14 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
* Get a new pointcut expression based on a target class's loader, rather
|
||||
* than the default.
|
||||
*/
|
||||
private PointcutExpression getFallbackPointcutExpression(
|
||||
Class<?> targetClass) {
|
||||
private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) {
|
||||
ClassLoader classLoader = targetClass.getClassLoader();
|
||||
return classLoader == null ? this.pointcutExpression : buildPointcutExpression(classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* A match test returned maybe - if there are any subtype sensitive variables
|
||||
* involved in the test (this, target, at_this, at_target, at_annotation) then
|
||||
* we say this is not a match as in Spring there will never be a different
|
||||
* runtime subtype.
|
||||
*/
|
||||
private boolean matchesIgnoringSubtypes(ShadowMatch shadowMatch) {
|
||||
return !(getRuntimeTestWalker(shadowMatch).testsSubtypeSensitiveVars());
|
||||
}
|
||||
|
||||
private boolean matchesTarget(ShadowMatch shadowMatch, Class<?> targetClass) {
|
||||
return getRuntimeTestWalker(shadowMatch).testTargetInstanceOfResidue(targetClass);
|
||||
return (classLoader != null ? buildPointcutExpression(classLoader) : this.pointcutExpression);
|
||||
}
|
||||
|
||||
private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
|
||||
if (shadowMatch instanceof DefensiveShadowMatch) {
|
||||
return new RuntimeTestWalker(((DefensiveShadowMatch)shadowMatch).primary);
|
||||
return new RuntimeTestWalker(((DefensiveShadowMatch) shadowMatch).primary);
|
||||
}
|
||||
return new RuntimeTestWalker(shadowMatch);
|
||||
}
|
||||
@@ -417,7 +409,8 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
try {
|
||||
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
} catch (ReflectionWorld.ReflectionWorldException e) {
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex2) {
|
||||
if (targetMethod == originalMethod) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
}
|
||||
@@ -425,21 +418,22 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(originalMethod);
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex2) {
|
||||
catch (ReflectionWorld.ReflectionWorldException ex3) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's simply consider this method as non-matching.
|
||||
methodToMatch = originalMethod;
|
||||
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
try {
|
||||
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
} catch (ReflectionWorld.ReflectionWorldException e2) {
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex4) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shadowMatch.maybeMatches() && fallbackPointcutExpression!=null) {
|
||||
if (shadowMatch.maybeMatches() && fallbackPointcutExpression != null) {
|
||||
shadowMatch = new DefensiveShadowMatch(shadowMatch,
|
||||
fallbackPointcutExpression.matchesMethodExecution(methodToMatch));
|
||||
}
|
||||
@@ -620,9 +614,11 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
this.shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||
}
|
||||
|
||||
|
||||
private static class DefensiveShadowMatch implements ShadowMatch {
|
||||
|
||||
private final ShadowMatch primary;
|
||||
|
||||
private final ShadowMatch other;
|
||||
|
||||
public DefensiveShadowMatch(ShadowMatch primary, ShadowMatch other) {
|
||||
@@ -632,35 +628,34 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
@Override
|
||||
public boolean alwaysMatches() {
|
||||
return primary.alwaysMatches();
|
||||
return this.primary.alwaysMatches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean maybeMatches() {
|
||||
return primary.maybeMatches();
|
||||
return this.primary.maybeMatches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean neverMatches() {
|
||||
return primary.neverMatches();
|
||||
return this.primary.neverMatches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JoinPointMatch matchesJoinPoint(Object thisObject,
|
||||
Object targetObject, Object[] args) {
|
||||
public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) {
|
||||
try {
|
||||
return primary.matchesJoinPoint(thisObject, targetObject, args);
|
||||
} catch (ReflectionWorldException e) {
|
||||
return other.matchesJoinPoint(thisObject, targetObject, args);
|
||||
return this.primary.matchesJoinPoint(thisObject, targetObject, args);
|
||||
}
|
||||
catch (ReflectionWorldException ex) {
|
||||
return this.other.matchesJoinPoint(thisObject, targetObject, args);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMatchingContext(MatchingContext aMatchContext) {
|
||||
primary.setMatchingContext(aMatchContext);
|
||||
other.setMatchingContext(aMatchContext);
|
||||
this.primary.setMatchingContext(aMatchContext);
|
||||
this.other.setMatchingContext(aMatchContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -18,6 +18,8 @@ package org.springframework.aop.aspectj;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.aspectj.weaver.ReferenceType;
|
||||
import org.aspectj.weaver.ReferenceTypeDelegate;
|
||||
import org.aspectj.weaver.ResolvedType;
|
||||
import org.aspectj.weaver.ast.And;
|
||||
import org.aspectj.weaver.ast.Call;
|
||||
@@ -30,6 +32,7 @@ import org.aspectj.weaver.ast.Not;
|
||||
import org.aspectj.weaver.ast.Or;
|
||||
import org.aspectj.weaver.ast.Test;
|
||||
import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
|
||||
import org.aspectj.weaver.reflect.ReflectionBasedReferenceTypeDelegate;
|
||||
import org.aspectj.weaver.reflect.ReflectionVar;
|
||||
import org.aspectj.weaver.reflect.ShadowMatchImpl;
|
||||
import org.aspectj.weaver.tools.ShadowMatch;
|
||||
@@ -55,25 +58,36 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
class RuntimeTestWalker {
|
||||
|
||||
private static final Field residualTestField;
|
||||
|
||||
private static final Field varTypeField;
|
||||
|
||||
private static final Field myClassField;
|
||||
|
||||
|
||||
static {
|
||||
try {
|
||||
residualTestField = ShadowMatchImpl.class.getDeclaredField("residualTest");
|
||||
varTypeField = ReflectionVar.class.getDeclaredField("varType");
|
||||
myClassField = ReflectionBasedReferenceTypeDelegate.class.getDeclaredField("myClass");
|
||||
}
|
||||
catch (NoSuchFieldException ex) {
|
||||
throw new IllegalStateException("The version of aspectjtools.jar / aspectjweaver.jar " +
|
||||
"on the classpath is incompatible with this version of Spring: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final Test runtimeTest;
|
||||
|
||||
|
||||
public RuntimeTestWalker(ShadowMatch shadowMatch) {
|
||||
ShadowMatchImpl shadowMatchImplementation = (ShadowMatchImpl) shadowMatch;
|
||||
try {
|
||||
Field testField = shadowMatchImplementation.getClass().getDeclaredField("residualTest");
|
||||
ReflectionUtils.makeAccessible(testField);
|
||||
this.runtimeTest = (Test) testField.get(shadowMatch);
|
||||
ReflectionUtils.makeAccessible(residualTestField);
|
||||
this.runtimeTest = (Test) residualTestField.get(shadowMatch);
|
||||
}
|
||||
catch (NoSuchFieldException noSuchFieldEx) {
|
||||
throw new IllegalStateException("The version of aspectjtools.jar / aspectjweaver.jar " +
|
||||
"on the classpath is incompatible with this version of Spring: Expected field " +
|
||||
"'runtimeTest' is not present on ShadowMatchImpl class.");
|
||||
}
|
||||
catch (IllegalAccessException illegalAccessEx) {
|
||||
// Famous last words... but I don't see how this can happen given the
|
||||
// makeAccessible call above
|
||||
throw new IllegalStateException("Unable to access ShadowMatchImpl.residualTest field");
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,19 +163,11 @@ class RuntimeTestWalker {
|
||||
|
||||
protected int getVarType(ReflectionVar v) {
|
||||
try {
|
||||
Field varTypeField = ReflectionVar.class.getDeclaredField("varType");
|
||||
ReflectionUtils.makeAccessible(varTypeField);
|
||||
return (Integer) varTypeField.get(v);
|
||||
}
|
||||
catch (NoSuchFieldException noSuchFieldEx) {
|
||||
throw new IllegalStateException("the version of aspectjtools.jar / aspectjweaver.jar " +
|
||||
"on the classpath is incompatible with this version of Spring:- expected field " +
|
||||
"'varType' is not present on ReflectionVar class");
|
||||
}
|
||||
catch (IllegalAccessException illegalAccessEx) {
|
||||
// Famous last words... but I don't see how this can happen given the
|
||||
// makeAccessible call above
|
||||
throw new IllegalStateException("Unable to access ReflectionVar.varType field");
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,9 +175,11 @@ class RuntimeTestWalker {
|
||||
|
||||
private static abstract class InstanceOfResidueTestVisitor extends TestVisitorAdapter {
|
||||
|
||||
private Class<?> matchClass;
|
||||
private final Class<?> matchClass;
|
||||
|
||||
private boolean matches;
|
||||
private int matchVarType;
|
||||
|
||||
private final int matchVarType;
|
||||
|
||||
public InstanceOfResidueTestVisitor(Class<?> matchClass, boolean defaultMatches, int matchVarType) {
|
||||
this.matchClass = matchClass;
|
||||
@@ -181,19 +189,34 @@ class RuntimeTestWalker {
|
||||
|
||||
public boolean instanceOfMatches(Test test) {
|
||||
test.accept(this);
|
||||
return matches;
|
||||
return this.matches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Instanceof i) {
|
||||
ResolvedType type = (ResolvedType) i.getType();
|
||||
int varType = getVarType((ReflectionVar) i.getVar());
|
||||
if (varType != this.matchVarType) {
|
||||
return;
|
||||
}
|
||||
Class<?> typeClass = null;
|
||||
ResolvedType type = (ResolvedType) i.getType();
|
||||
if (type instanceof ReferenceType) {
|
||||
ReferenceTypeDelegate delegate = ((ReferenceType) type).getDelegate();
|
||||
if (delegate instanceof ReflectionBasedReferenceTypeDelegate) {
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(myClassField);
|
||||
typeClass = (Class<?>) myClassField.get(delegate);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
Class<?> typeClass = ClassUtils.forName(type.getName(), this.matchClass.getClassLoader());
|
||||
// Don't use ReflectionType.isAssignableFrom() as it won't be aware of (Spring) mixins
|
||||
// Don't use ResolvedType.isAssignableFrom() as it won't be aware of (Spring) mixins
|
||||
if (typeClass == null) {
|
||||
typeClass = ClassUtils.forName(type.getName(), this.matchClass.getClassLoader());
|
||||
}
|
||||
this.matches = typeClass.isAssignableFrom(this.matchClass);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
@@ -237,8 +260,11 @@ class RuntimeTestWalker {
|
||||
private static class SubtypeSensitiveVarTypeTestVisitor extends TestVisitorAdapter {
|
||||
|
||||
private final Object thisObj = new Object();
|
||||
|
||||
private final Object targetObj = new Object();
|
||||
|
||||
private final Object[] argsObjs = new Object[0];
|
||||
|
||||
private boolean testsSubtypeSensitiveVars = false;
|
||||
|
||||
public boolean testsSubtypeSensitiveVars(Test aTest) {
|
||||
@@ -249,8 +275,8 @@ class RuntimeTestWalker {
|
||||
@Override
|
||||
public void visit(Instanceof i) {
|
||||
ReflectionVar v = (ReflectionVar) i.getVar();
|
||||
Object varUnderTest = v.getBindingAtJoinPoint(thisObj,targetObj,argsObjs);
|
||||
if ((varUnderTest == thisObj) || (varUnderTest == targetObj)) {
|
||||
Object varUnderTest = v.getBindingAtJoinPoint(this.thisObj, this.targetObj, this.argsObjs);
|
||||
if (varUnderTest == this.thisObj || varUnderTest == this.targetObj) {
|
||||
this.testsSubtypeSensitiveVars = true;
|
||||
}
|
||||
}
|
||||
@@ -260,7 +286,7 @@ class RuntimeTestWalker {
|
||||
// If you thought things were bad before, now we sink to new levels of horror...
|
||||
ReflectionVar v = (ReflectionVar) hasAnn.getVar();
|
||||
int varType = getVarType(v);
|
||||
if ((varType == AT_THIS_VAR) || (varType == AT_TARGET_VAR) || (varType == AT_ANNOTATION_VAR)) {
|
||||
if (varType == AT_THIS_VAR || varType == AT_TARGET_VAR || varType == AT_ANNOTATION_VAR) {
|
||||
this.testsSubtypeSensitiveVars = true;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -67,7 +67,7 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
|
||||
}
|
||||
|
||||
public void setAspectJAdvisorFactory(AspectJAdvisorFactory aspectJAdvisorFactory) {
|
||||
Assert.notNull(this.aspectJAdvisorFactory, "AspectJAdvisorFactory must not be null");
|
||||
Assert.notNull(aspectJAdvisorFactory, "AspectJAdvisorFactory must not be null");
|
||||
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,6 +37,7 @@ import org.springframework.aop.RawTargetAccess;
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.cglib.core.CodeGenerationException;
|
||||
import org.springframework.cglib.core.SpringNamingPolicy;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.CallbackFilter;
|
||||
import org.springframework.cglib.proxy.Dispatcher;
|
||||
@@ -45,7 +46,7 @@ import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.cglib.proxy.MethodInterceptor;
|
||||
import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.cglib.proxy.NoOp;
|
||||
import org.springframework.cglib.transform.impl.MemorySafeUndeclaredThrowableStrategy;
|
||||
import org.springframework.cglib.transform.impl.UndeclaredThrowableStrategy;
|
||||
import org.springframework.core.SmartClassLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -183,19 +184,19 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
}
|
||||
}
|
||||
enhancer.setSuperclass(proxySuperClass);
|
||||
enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
|
||||
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
|
||||
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
||||
enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));
|
||||
|
||||
Callback[] callbacks = getCallbacks(rootClass);
|
||||
Class<?>[] types = new Class<?>[callbacks.length];
|
||||
|
||||
for (int x = 0; x < types.length; x++) {
|
||||
types[x] = callbacks[x].getClass();
|
||||
}
|
||||
|
||||
enhancer.setCallbackTypes(types);
|
||||
// fixedInterceptorMap only populated at this point, after getCallbacks call above
|
||||
enhancer.setCallbackFilter(new ProxyCallbackFilter(
|
||||
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
|
||||
enhancer.setCallbackTypes(types);
|
||||
|
||||
// Generate the proxy class and create a proxy instance.
|
||||
return createProxyClassAndInstance(enhancer, callbacks);
|
||||
@@ -219,12 +220,11 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
}
|
||||
|
||||
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
|
||||
|
||||
enhancer.setInterceptDuringConstruction(false);
|
||||
enhancer.setCallbacks(callbacks);
|
||||
|
||||
return this.constructorArgs == null ? enhancer.create() : enhancer.create(
|
||||
this.constructorArgTypes, this.constructorArgs);
|
||||
return (this.constructorArgs != null ?
|
||||
enhancer.create(this.constructorArgTypes, this.constructorArgs) :
|
||||
enhancer.create());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,8 +314,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
Callback[] fixedCallbacks = new Callback[methods.length];
|
||||
this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);
|
||||
|
||||
// TODO: small memory optimisation 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(
|
||||
@@ -342,16 +341,15 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
*/
|
||||
private static Object processReturnType(Object proxy, Object target, Method method, Object retVal) {
|
||||
// Massage return value if necessary
|
||||
if (retVal != null && retVal == target &&
|
||||
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
|
||||
// Special case: it returned "this".
|
||||
// Note that we can't help if the target sets a reference
|
||||
// to itself in another returned object.
|
||||
if (retVal != null && retVal == target && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
|
||||
// Special case: it returned "this". Note that we can't help
|
||||
// if the target sets a reference to itself in another returned object.
|
||||
retVal = proxy;
|
||||
}
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
|
||||
throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
|
||||
throw new AopInvocationException(
|
||||
"Null return value from advice does not match primitive return type for: " + method);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
@@ -864,7 +862,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof ProxyCallbackFilter)) {
|
||||
|
||||
+4
-5
@@ -16,9 +16,9 @@
|
||||
|
||||
package org.springframework.aop.framework;
|
||||
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.Enhancer;
|
||||
import org.springframework.cglib.proxy.Factory;
|
||||
@@ -54,15 +54,14 @@ class ObjenesisCglibAopProxy extends CglibAopProxy {
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
|
||||
try {
|
||||
Factory factory = (Factory) objenesis.newInstance(enhancer.createClass());
|
||||
Factory factory = (Factory) this.objenesis.newInstance(enhancer.createClass());
|
||||
factory.setCallbacks(callbacks);
|
||||
return factory;
|
||||
}
|
||||
catch (ObjenesisException ex) {
|
||||
// Fallback to Cglib on unsupported JVMs
|
||||
// Fallback to regular proxy construction on unsupported JVMs
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Unable to instantiate proxy using Objenesis, falling back "
|
||||
+ "to regular proxy construction", ex);
|
||||
logger.debug("Unable to instantiate proxy using Objenesis, falling back to regular proxy construction", ex);
|
||||
}
|
||||
return super.createProxyClassAndInstance(enhancer, callbacks);
|
||||
}
|
||||
|
||||
+55
-13
@@ -40,14 +40,18 @@ import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
|
||||
import org.springframework.aop.target.SingletonTargetSource;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
import org.springframework.beans.factory.Aware;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
|
||||
@@ -465,12 +469,12 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
|
||||
proxyFactory.copyFrom(this);
|
||||
|
||||
if (!shouldProxyTargetClass(beanClass, beanName)) {
|
||||
// Must allow for introductions; can't just set interfaces to
|
||||
// the target's interfaces only.
|
||||
Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
|
||||
for (Class<?> targetInterface : targetInterfaces) {
|
||||
proxyFactory.addInterface(targetInterface);
|
||||
if (!proxyFactory.isProxyTargetClass()) {
|
||||
if (shouldProxyTargetClass(beanClass, beanName)) {
|
||||
proxyFactory.setProxyTargetClass(true);
|
||||
}
|
||||
else {
|
||||
evaluateProxyInterfaces(beanClass, proxyFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,10 +495,8 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given bean should be proxied with its target
|
||||
* class rather than its interfaces. Checks the
|
||||
* {@link #setProxyTargetClass "proxyTargetClass" setting} as well as the
|
||||
* {@link AutoProxyUtils#PRESERVE_TARGET_CLASS_ATTRIBUTE "preserveTargetClass" attribute}
|
||||
* Determine whether the given bean should be proxied with its target class rather than its interfaces.
|
||||
* <p>Checks the {@link AutoProxyUtils#PRESERVE_TARGET_CLASS_ATTRIBUTE "preserveTargetClass" attribute}
|
||||
* of the corresponding bean definition.
|
||||
* @param beanClass the class of the bean
|
||||
* @param beanName the name of the bean
|
||||
@@ -502,9 +504,49 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
* @see AutoProxyUtils#shouldProxyTargetClass
|
||||
*/
|
||||
protected boolean shouldProxyTargetClass(Class<?> beanClass, String beanName) {
|
||||
return (isProxyTargetClass() ||
|
||||
(this.beanFactory instanceof ConfigurableListableBeanFactory &&
|
||||
AutoProxyUtils.shouldProxyTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName)));
|
||||
return (this.beanFactory instanceof ConfigurableListableBeanFactory &&
|
||||
AutoProxyUtils.shouldProxyTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the interfaces on the given bean class and apply them to the ProxyFactory,
|
||||
* if appropriate.
|
||||
* <p>Calls {@link #isConfigurationCallbackInterface} to filter for reasonable
|
||||
* proxy interfaces, falling back to a target-class proxy otherwise.
|
||||
* @param beanClass the class of the bean
|
||||
* @param proxyFactory the ProxyFactory for the bean
|
||||
*/
|
||||
private void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
|
||||
Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
|
||||
boolean hasReasonableProxyInterface = false;
|
||||
for (Class<?> ifc : targetInterfaces) {
|
||||
if (!isConfigurationCallbackInterface(ifc) && ifc.getMethods().length > 0) {
|
||||
hasReasonableProxyInterface = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasReasonableProxyInterface) {
|
||||
// Must allow for introductions; can't just set interfaces to the target's interfaces only.
|
||||
for (Class<?> ifc : targetInterfaces) {
|
||||
proxyFactory.addInterface(ifc);
|
||||
}
|
||||
}
|
||||
else {
|
||||
proxyFactory.setProxyTargetClass(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given interface is just a container callback and
|
||||
* therefore not to be considered as a reasonable proxy interface.
|
||||
* <p>If no reasonable proxy interface is found for a given bean, it will get
|
||||
* proxied with its full target class, assuming that as the user's intention.
|
||||
* @param ifc the interface to check
|
||||
* @return whether the given interface is just a container callback
|
||||
*/
|
||||
protected boolean isConfigurationCallbackInterface(Class<?> ifc) {
|
||||
return (ifc.equals(InitializingBean.class) || ifc.equals(DisposableBean.class) ||
|
||||
ObjectUtils.containsElement(ifc.getInterfaces(), Aware.class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,7 +58,7 @@ public abstract class ScopedProxyUtils {
|
||||
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
|
||||
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
|
||||
proxyDefinition.setSource(definition.getSource());
|
||||
proxyDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
proxyDefinition.setRole(targetDefinition.getRole());
|
||||
|
||||
proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
|
||||
if (proxyTargetClass) {
|
||||
|
||||
+27
-24
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -29,17 +29,16 @@ import org.springframework.util.StringUtils;
|
||||
* <ul>
|
||||
* <li>pattern: regular expression for the fully-qualified method names to match.
|
||||
* The exact regexp syntax will depend on the subclass (e.g. Perl5 regular expressions)
|
||||
* <li>patterns: alternative property taking a String array of patterns. The result will
|
||||
* be the union of these patterns.
|
||||
* <li>patterns: alternative property taking a String array of patterns.
|
||||
* The result will be the union of these patterns.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Note: the regular expressions must be a match. For example,
|
||||
* {@code .*get.*} will match com.mycom.Foo.getBar().
|
||||
* {@code get.*} will not.
|
||||
*
|
||||
* <p>This base class is serializable. Subclasses should declare all fields transient
|
||||
* - the initPatternRepresentation method in this class will be invoked again on the
|
||||
* client side on deserialization.
|
||||
* <p>This base class is serializable. Subclasses should declare all fields transient;
|
||||
* the {@link #initPatternRepresentation} method will be invoked again on deserialization.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -51,10 +50,14 @@ import org.springframework.util.StringUtils;
|
||||
public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPointcut
|
||||
implements Serializable {
|
||||
|
||||
/** Regular expressions to match */
|
||||
/**
|
||||
* Regular expressions to match.
|
||||
*/
|
||||
private String[] patterns = new String[0];
|
||||
|
||||
/** Regular expressions <strong>not</strong> to match */
|
||||
/**
|
||||
* Regular expressions <strong>not</strong> to match.
|
||||
*/
|
||||
private String[] excludedPatterns = new String[0];
|
||||
|
||||
|
||||
@@ -64,15 +67,15 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
|
||||
* @see #setPatterns
|
||||
*/
|
||||
public void setPattern(String pattern) {
|
||||
setPatterns(new String[] {pattern});
|
||||
setPatterns(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the regular expressions defining methods to match.
|
||||
* Matching will be the union of all these; if any match,
|
||||
* the pointcut matches.
|
||||
* Matching will be the union of all these; if any match, the pointcut matches.
|
||||
* @see #setPattern
|
||||
*/
|
||||
public void setPatterns(String[] patterns) {
|
||||
public void setPatterns(String... patterns) {
|
||||
Assert.notEmpty(patterns, "'patterns' must not be empty");
|
||||
this.patterns = new String[patterns.length];
|
||||
for (int i = 0; i < patterns.length; i++) {
|
||||
@@ -94,15 +97,15 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
|
||||
* @see #setExcludedPatterns
|
||||
*/
|
||||
public void setExcludedPattern(String excludedPattern) {
|
||||
setExcludedPatterns(new String[] {excludedPattern});
|
||||
setExcludedPatterns(excludedPattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the regular expressions defining methods to match for exclusion.
|
||||
* Matching will be the union of all these; if any match,
|
||||
* the pointcut matches.
|
||||
* Matching will be the union of all these; if any match, the pointcut matches.
|
||||
* @see #setExcludedPattern
|
||||
*/
|
||||
public void setExcludedPatterns(String[] excludedPatterns) {
|
||||
public void setExcludedPatterns(String... excludedPatterns) {
|
||||
Assert.notEmpty(excludedPatterns, "'excludedPatterns' must not be empty");
|
||||
this.excludedPatterns = new String[excludedPatterns.length];
|
||||
for (int i = 0; i < excludedPatterns.length; i++) {
|
||||
@@ -173,18 +176,18 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
|
||||
protected abstract void initExcludedPatternRepresentation(String[] patterns) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Does the pattern at the given index match this string?
|
||||
* @param pattern {@code String} pattern to match
|
||||
* @param patternIndex index of pattern from 0
|
||||
* @return {@code true} if there is a match, else {@code false}.
|
||||
* Does the pattern at the given index match the given String?
|
||||
* @param pattern the {@code String} pattern to match
|
||||
* @param patternIndex index of pattern (starting from 0)
|
||||
* @return {@code true} if there is a match, {@code false} otherwise
|
||||
*/
|
||||
protected abstract boolean matches(String pattern, int patternIndex);
|
||||
|
||||
/**
|
||||
* Does the exclusion pattern at the given index match this string?
|
||||
* @param pattern {@code String} pattern to match.
|
||||
* @param patternIndex index of pattern starting from 0.
|
||||
* @return {@code true} if there is a match, else {@code false}.
|
||||
* Does the exclusion pattern at the given index match the given String?
|
||||
* @param pattern the {@code String} pattern to match
|
||||
* @param patternIndex index of pattern (starting from 0)
|
||||
* @return {@code true} if there is a match, {@code false} otherwise
|
||||
*/
|
||||
protected abstract boolean matchesExclusion(String pattern, int patternIndex);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -23,8 +23,7 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Static utility methods for composing
|
||||
* {@link org.springframework.aop.ClassFilter ClassFilters}.
|
||||
* Static utility methods for composing {@link ClassFilter ClassFilters}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
@@ -98,8 +97,8 @@ public abstract class ClassFilters {
|
||||
|
||||
@Override
|
||||
public boolean matches(Class<?> clazz) {
|
||||
for (int i = 0; i < this.filters.length; i++) {
|
||||
if (this.filters[i].matches(clazz)) {
|
||||
for (ClassFilter filter : this.filters) {
|
||||
if (filter.matches(clazz)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -133,8 +132,8 @@ public abstract class ClassFilters {
|
||||
|
||||
@Override
|
||||
public boolean matches(Class<?> clazz) {
|
||||
for (int i = 0; i < this.filters.length; i++) {
|
||||
if (!this.filters[i].matches(clazz)) {
|
||||
for (ClassFilter filter : this.filters) {
|
||||
if (!filter.matches(clazz)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -180,7 +180,6 @@ public class ComposablePointcut implements Pointcut, Serializable {
|
||||
return this.methodMatcher;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
@@ -189,7 +188,6 @@ public class ComposablePointcut implements Pointcut, Serializable {
|
||||
if (!(other instanceof ComposablePointcut)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ComposablePointcut that = (ComposablePointcut) other;
|
||||
return ObjectUtils.nullSafeEquals(that.classFilter, this.classFilter) &&
|
||||
ObjectUtils.nullSafeEquals(that.methodMatcher, this.methodMatcher);
|
||||
@@ -209,8 +207,7 @@ public class ComposablePointcut implements Pointcut, Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ComposablePointcut: ClassFilter [" + this.classFilter +
|
||||
"], MethodMatcher [" + this.methodMatcher + "]";
|
||||
return "ComposablePointcut: " + this.classFilter + ", " +this.methodMatcher;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,12 +25,11 @@ import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Static utility methods for composing
|
||||
* {@link org.springframework.aop.MethodMatcher MethodMatchers}.
|
||||
* Static utility methods for composing {@link MethodMatcher MethodMatchers}.
|
||||
*
|
||||
* <p>A MethodMatcher may be evaluated statically (based on method
|
||||
* and target class) or need further evaluation dynamically
|
||||
* (based on arguments at the time of method invocation).
|
||||
* <p>A MethodMatcher may be evaluated statically (based on method and target
|
||||
* class) or need further evaluation dynamically (based on arguments at the
|
||||
* time of method invocation).
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
|
||||
+23
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -66,4 +66,26 @@ public class AnnotationClassFilter implements ClassFilter {
|
||||
clazz.isAnnotationPresent(this.annotationType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof AnnotationClassFilter)) {
|
||||
return false;
|
||||
}
|
||||
AnnotationClassFilter otherCf = (AnnotationClassFilter) other;
|
||||
return (this.annotationType.equals(otherCf.annotationType) && this.checkInherited == otherCf.checkInherited);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.annotationType.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + ": " + this.annotationType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+32
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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
|
||||
@@ -100,6 +101,36 @@ public class AnnotationMatchingPointcut implements Pointcut {
|
||||
return this.methodMatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof AnnotationMatchingPointcut)) {
|
||||
return false;
|
||||
}
|
||||
AnnotationMatchingPointcut that = (AnnotationMatchingPointcut) other;
|
||||
return ObjectUtils.nullSafeEquals(that.classFilter, this.classFilter) &&
|
||||
ObjectUtils.nullSafeEquals(that.methodMatcher, this.methodMatcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int 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
|
||||
public String toString() {
|
||||
return "AnnotationMatchingPointcut: " + this.classFilter + ", " +this.methodMatcher;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Factory method for an AnnotationMatchingPointcut that matches
|
||||
|
||||
+6
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -74,4 +74,9 @@ public class AnnotationMethodMatcher extends StaticMethodMatcher {
|
||||
return this.annotationType.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + ": " + this.annotationType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,12 +50,10 @@ import org.springframework.beans.factory.DisposableBean;
|
||||
* @see #releaseTarget
|
||||
* @see #destroy
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class AbstractPoolingTargetSource extends AbstractPrototypeBasedTargetSource
|
||||
implements PoolingConfig, DisposableBean {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
/** The maximum size of the pool */
|
||||
private int maxSize = -1;
|
||||
|
||||
|
||||
+2
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,11 +43,9 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
* @see ThreadLocalTargetSource
|
||||
* @see CommonsPoolTargetSource
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFactoryBasedTargetSource {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
super.setBeanFactory(beanFactory);
|
||||
|
||||
+11
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,8 +24,8 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.core.Constants;
|
||||
|
||||
/**
|
||||
* TargetSource implementation that holds objects in a configurable
|
||||
* Jakarta Commons Pool.
|
||||
* {@link org.springframework.aop.TargetSource} implementation that holds
|
||||
* objects in a configurable Apache Commons Pool.
|
||||
*
|
||||
* <p>By default, an instance of {@code GenericObjectPool} is created.
|
||||
* Subclasses may change the type of {@code ObjectPool} used by
|
||||
@@ -40,8 +40,12 @@ import org.springframework.core.Constants;
|
||||
* <p>The {@code testOnBorrow}, {@code testOnReturn} and {@code testWhileIdle}
|
||||
* properties are explicitly not mirrored because the implementation of
|
||||
* {@code PoolableObjectFactory} used by this class does not implement
|
||||
* meaningful validation. All exposed Commons Pool properties use the corresponding
|
||||
* Commons Pool defaults: for example,
|
||||
* meaningful validation. All exposed Commons Pool properties use the
|
||||
* corresponding Commons Pool defaults.
|
||||
*
|
||||
* <p>Compatible with Apache Commons Pool 1.5.x and 1.6.
|
||||
* Note that this class doesn't declare Commons Pool 1.6's generic type
|
||||
* in order to remain compatible with Commons Pool 1.5.x at runtime.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
@@ -55,10 +59,8 @@ import org.springframework.core.Constants;
|
||||
* @see #setTimeBetweenEvictionRunsMillis
|
||||
* @see #setMinEvictableIdleTimeMillis
|
||||
*/
|
||||
public class CommonsPoolTargetSource extends AbstractPoolingTargetSource
|
||||
implements PoolableObjectFactory {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@SuppressWarnings({"rawtypes", "unchecked", "serial"})
|
||||
public class CommonsPoolTargetSource extends AbstractPoolingTargetSource implements PoolableObjectFactory {
|
||||
|
||||
private static final Constants constants = new Constants(GenericObjectPool.class);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,9 +19,11 @@ package org.springframework.aop.target;
|
||||
import org.springframework.beans.BeansException;
|
||||
|
||||
/**
|
||||
* TargetSource that creates a new instance of the target bean for each
|
||||
* request, destroying each instance on release (after each request).
|
||||
* Obtains bean instances from its containing
|
||||
* {@link org.springframework.aop.TargetSource} implementation that
|
||||
* creates a new instance of the target bean for each request,
|
||||
* destroying each instance on release (after each request).
|
||||
*
|
||||
* <p>Obtains bean instances from its containing
|
||||
* {@link org.springframework.beans.factory.BeanFactory}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
@@ -29,10 +31,9 @@ import org.springframework.beans.BeansException;
|
||||
* @see #setBeanFactory
|
||||
* @see #setTargetBeanName
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class PrototypeTargetSource extends AbstractPrototypeBasedTargetSource {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Obtain a new prototype instance for every call.
|
||||
* @see #newPrototypeInstance()
|
||||
|
||||
+8
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,9 +27,10 @@ import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
|
||||
/**
|
||||
* Alternative to an object pool. This TargetSource uses a threading model in which
|
||||
* every thread has its own copy of the target. There's no contention for targets.
|
||||
* Target object creation is kept to a minimum on the running server.
|
||||
* Alternative to an object pool. This {@link org.springframework.aop.TargetSource}
|
||||
* uses a threading model in which every thread has its own copy of the target.
|
||||
* There's no contention for targets. Target object creation is kept to a minimum
|
||||
* on the running server.
|
||||
*
|
||||
* <p>Application code is written as to a normal pool; callers can't assume they
|
||||
* will be dealing with the same instance in invocations in different threads.
|
||||
@@ -47,11 +48,10 @@ import org.springframework.core.NamedThreadLocal;
|
||||
* @see ThreadLocalTargetSourceStats
|
||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
|
||||
implements ThreadLocalTargetSourceStats, DisposableBean {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ThreadLocal holding the target associated with the current
|
||||
* thread. Unlike most ThreadLocals, which are static, this variable
|
||||
@@ -81,10 +81,8 @@ public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
|
||||
Object target = this.targetInThread.get();
|
||||
if (target == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("No target for prototype '" + getTargetBeanName() +
|
||||
"' bound to thread: " +
|
||||
"creating one and binding it to thread '" +
|
||||
Thread.currentThread().getName() + "'");
|
||||
logger.debug("No target for prototype '" + getTargetBeanName() + "' bound to thread: " +
|
||||
"creating one and binding it to thread '" + Thread.currentThread().getName() + "'");
|
||||
}
|
||||
// Associate target with ThreadLocal.
|
||||
target = newPrototypeInstance();
|
||||
|
||||
@@ -197,7 +197,7 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="order" type="xsd:int">
|
||||
<xsd:attribute name="order" type="xsd:token">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.core.Ordered"><![CDATA[
|
||||
Controls the ordering of the execution of this aspect when multiple
|
||||
@@ -386,7 +386,7 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="order" type="xsd:int">
|
||||
<xsd:attribute name="order" type="xsd:token">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.core.Ordered"><![CDATA[
|
||||
Controls the ordering of the execution of this advice when multiple
|
||||
|
||||
+6
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,15 +15,6 @@
|
||||
*/
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -46,7 +37,9 @@ import org.aspectj.lang.annotation.DeclareParents;
|
||||
import org.aspectj.lang.annotation.DeclarePrecedence;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
@@ -66,6 +59,9 @@ import test.aop.Lockable;
|
||||
import test.aop.PerTargetAspect;
|
||||
import test.aop.TwoAdviceAspect;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Abstract tests for AspectJAdvisorFactory.
|
||||
* See subclasses for tests of concrete factories.
|
||||
|
||||
+3
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,10 +16,6 @@
|
||||
|
||||
package org.springframework.aop.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -27,6 +23,8 @@ import org.junit.Test;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.util.SerializationTestUtils;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
* @author Dmitriy Kopylenko
|
||||
|
||||
@@ -61,7 +61,7 @@ compileTestJava {
|
||||
ant.taskdef(resource: "org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties",
|
||||
classpath: configurations.ajc.asPath)
|
||||
|
||||
ant.iajc(source: compileJava.sourceCompatibility, target: compileJava.targetCompatibility,
|
||||
ant.iajc(source: sourceCompatibility, target: targetCompatibility,
|
||||
maxmem: "1024m", fork: "true", Xlint: "ignore",
|
||||
destDir: outputDir.absolutePath,
|
||||
aspectPath: jar.archivePath,
|
||||
|
||||
+126
-72
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,86 +18,140 @@ package org.springframework.mock.staticmock;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Abstract aspect to enable mocking of methods picked out by a pointcut.
|
||||
* Sub-aspects must define the mockStaticsTestMethod() pointcut to
|
||||
* indicate call stacks when mocking should be triggered, and the
|
||||
* methodToMock() pointcut to pick out a method invocations to mock.
|
||||
*
|
||||
* <p>Sub-aspects must define:
|
||||
* <ul>
|
||||
* <li>The {@link #mockStaticsTestMethod()} pointcut to indicate call stacks
|
||||
* when mocking should be triggered
|
||||
* <li>The {@link #methodToMock()} pointcut to pick out method invocations to mock
|
||||
* </ul>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) {
|
||||
|
||||
protected abstract pointcut mockStaticsTestMethod();
|
||||
|
||||
protected abstract pointcut methodToMock();
|
||||
private final Expectations expectations = new Expectations();
|
||||
|
||||
private boolean recording = true;
|
||||
|
||||
static enum CallResponse { nothing, return_, throw_ };
|
||||
|
||||
// Represents a list of expected calls to static entity methods
|
||||
protected void expectReturnInternal(Object retVal) {
|
||||
if (!recording) {
|
||||
throw new IllegalStateException("Not recording: Cannot set return value");
|
||||
}
|
||||
expectations.expectReturn(retVal);
|
||||
}
|
||||
|
||||
protected void expectThrowInternal(Throwable throwable) {
|
||||
if (!recording) {
|
||||
throw new IllegalStateException("Not recording: Cannot set throwable value");
|
||||
}
|
||||
expectations.expectThrow(throwable);
|
||||
}
|
||||
|
||||
protected void playbackInternal() {
|
||||
recording = false;
|
||||
}
|
||||
|
||||
protected void verifyInternal() {
|
||||
expectations.verify();
|
||||
}
|
||||
|
||||
protected void resetInternal() {
|
||||
expectations.reset();
|
||||
recording = true;
|
||||
}
|
||||
|
||||
|
||||
private static enum CallResponse {
|
||||
undefined, return_, throw_
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a list of expected calls to methods.
|
||||
*/
|
||||
// Public to allow inserted code to access: is this normal??
|
||||
public class Expectations {
|
||||
|
||||
// Represents an expected call to a static entity method
|
||||
/**
|
||||
* Represents an expected call to a method.
|
||||
*/
|
||||
private class Call {
|
||||
|
||||
private final String signature;
|
||||
private final Object[] args;
|
||||
|
||||
private CallResponse responseType = CallResponse.undefined;
|
||||
private Object responseObject; // return value or throwable
|
||||
private CallResponse responseType = CallResponse.nothing;
|
||||
|
||||
public Call(String name, Object[] args) {
|
||||
this.signature = name;
|
||||
|
||||
Call(String signature, Object[] args) {
|
||||
this.signature = signature;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public boolean hasResponseSpecified() {
|
||||
return responseType != CallResponse.nothing;
|
||||
boolean responseTypeAlreadySet() {
|
||||
return responseType != CallResponse.undefined;
|
||||
}
|
||||
|
||||
public void setReturnVal(Object retVal) {
|
||||
void setReturnValue(Object retVal) {
|
||||
this.responseObject = retVal;
|
||||
responseType = CallResponse.return_;
|
||||
}
|
||||
|
||||
public void setThrow(Throwable throwable) {
|
||||
void setThrowable(Throwable throwable) {
|
||||
this.responseObject = throwable;
|
||||
responseType = CallResponse.throw_;
|
||||
}
|
||||
|
||||
public Object returnValue(String lastSig, Object[] args) {
|
||||
Object returnValue(String lastSig, Object[] args) {
|
||||
checkSignature(lastSig, args);
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
public Object throwException(String lastSig, Object[] args) {
|
||||
Object throwException(String lastSig, Object[] args) {
|
||||
checkSignature(lastSig, args);
|
||||
throw (RuntimeException)responseObject;
|
||||
throw (RuntimeException) responseObject;
|
||||
}
|
||||
|
||||
private void checkSignature(String lastSig, Object[] args) {
|
||||
if (!signature.equals(lastSig)) {
|
||||
throw new IllegalArgumentException("Signature doesn't match");
|
||||
throw new IllegalArgumentException("Signatures do not match");
|
||||
}
|
||||
if (!Arrays.equals(this.args, args)) {
|
||||
throw new IllegalArgumentException("Arguments don't match");
|
||||
throw new IllegalArgumentException("Arguments do not match");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Call with signature [%s] and arguments %s", this.signature,
|
||||
ObjectUtils.nullSafeToString(args));
|
||||
}
|
||||
}
|
||||
|
||||
private List<Call> calls = new LinkedList<Call>();
|
||||
|
||||
// Calls already verified
|
||||
/**
|
||||
* The list of recorded calls.
|
||||
*/
|
||||
private final LinkedList<Call> calls = new LinkedList<Call>();
|
||||
|
||||
/**
|
||||
* The number of calls already verified.
|
||||
*/
|
||||
private int verified;
|
||||
|
||||
|
||||
public void verify() {
|
||||
if (verified != calls.size()) {
|
||||
throw new IllegalStateException("Expected " + calls.size() + " calls, received " + verified);
|
||||
throw new IllegalStateException("Expected " + calls.size() + " calls, but received " + verified);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,31 +159,32 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
|
||||
* Validate the call and provide the expected return value.
|
||||
*/
|
||||
public Object respond(String lastSig, Object[] args) {
|
||||
Call call = nextCall();
|
||||
CallResponse responseType = call.responseType;
|
||||
if (responseType == CallResponse.return_) {
|
||||
return call.returnValue(lastSig, args);
|
||||
Call c = nextCall();
|
||||
|
||||
switch (c.responseType) {
|
||||
case return_: {
|
||||
return c.returnValue(lastSig, args);
|
||||
}
|
||||
case throw_: {
|
||||
return c.throwException(lastSig, args);
|
||||
}
|
||||
default: {
|
||||
throw new IllegalStateException("Behavior of " + c + " not specified");
|
||||
}
|
||||
}
|
||||
else if (responseType == CallResponse.throw_) {
|
||||
return call.throwException(lastSig, args);
|
||||
}
|
||||
else if (responseType == CallResponse.nothing) {
|
||||
// do nothing
|
||||
}
|
||||
throw new IllegalStateException("Behavior of " + call + " not specified");
|
||||
}
|
||||
|
||||
private Call nextCall() {
|
||||
verified++;
|
||||
if (verified > calls.size()) {
|
||||
throw new IllegalStateException("Expected " + calls.size() + " calls, received " + verified);
|
||||
throw new IllegalStateException("Expected " + calls.size() + " calls, but received " + verified);
|
||||
}
|
||||
return calls.get(verified);
|
||||
// The 'verified' count is 1-based; whereas, 'calls' is 0-based.
|
||||
return calls.get(verified - 1);
|
||||
}
|
||||
|
||||
public void expectCall(String lastSig, Object lastArgs[]) {
|
||||
Call call = new Call(lastSig, lastArgs);
|
||||
calls.add(call);
|
||||
public void expectCall(String lastSig, Object[] lastArgs) {
|
||||
calls.add(new Call(lastSig, lastArgs));
|
||||
}
|
||||
|
||||
public boolean hasCalls() {
|
||||
@@ -137,31 +192,48 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
|
||||
}
|
||||
|
||||
public void expectReturn(Object retVal) {
|
||||
Call call = calls.get(calls.size() - 1);
|
||||
if (call.hasResponseSpecified()) {
|
||||
throw new IllegalStateException("No static method invoked before setting return value");
|
||||
Call c = calls.getLast();
|
||||
if (c.responseTypeAlreadySet()) {
|
||||
throw new IllegalStateException("No method invoked before setting return value");
|
||||
}
|
||||
call.setReturnVal(retVal);
|
||||
c.setReturnValue(retVal);
|
||||
}
|
||||
|
||||
public void expectThrow(Throwable throwable) {
|
||||
Call call = calls.get(calls.size() - 1);
|
||||
if (call.hasResponseSpecified()) {
|
||||
throw new IllegalStateException("No static method invoked before setting throwable");
|
||||
Call c = calls.getLast();
|
||||
if (c.responseTypeAlreadySet()) {
|
||||
throw new IllegalStateException("No method invoked before setting throwable");
|
||||
}
|
||||
call.setThrow(throwable);
|
||||
c.setThrowable(throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the internal state of this {@code Expectations} instance.
|
||||
*/
|
||||
public void reset() {
|
||||
this.calls.clear();
|
||||
this.verified = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private Expectations expectations = new Expectations();
|
||||
|
||||
/**
|
||||
* Pointcut that identifies call stacks when mocking should be triggered.
|
||||
*/
|
||||
protected abstract pointcut mockStaticsTestMethod();
|
||||
|
||||
/**
|
||||
* Pointcut that identifies which method invocations to mock.
|
||||
*/
|
||||
protected abstract pointcut methodToMock();
|
||||
|
||||
after() returning : mockStaticsTestMethod() {
|
||||
if (recording && (expectations.hasCalls())) {
|
||||
throw new IllegalStateException(
|
||||
"Calls recorded, yet playback state never reached: Create expectations then call "
|
||||
+ this.getClass().getSimpleName() + ".playback()");
|
||||
"Calls have been recorded, but playback state was never reached. Set expectations and then call "
|
||||
+ this.getClass().getSimpleName() + ".playback();");
|
||||
}
|
||||
expectations.verify();
|
||||
verifyInternal();
|
||||
}
|
||||
|
||||
Object around() : methodToMock() && cflowbelow(mockStaticsTestMethod()) {
|
||||
@@ -175,22 +247,4 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
|
||||
}
|
||||
}
|
||||
|
||||
public void expectReturnInternal(Object retVal) {
|
||||
if (!recording) {
|
||||
throw new IllegalStateException("Not recording: Cannot set return value");
|
||||
}
|
||||
expectations.expectReturn(retVal);
|
||||
}
|
||||
|
||||
public void expectThrowInternal(Throwable throwable) {
|
||||
if (!recording) {
|
||||
throw new IllegalStateException("Not recording: Cannot set throwable value");
|
||||
}
|
||||
expectations.expectThrow(throwable);
|
||||
}
|
||||
|
||||
public void playbackInternal() {
|
||||
recording = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+71
-23
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,50 +17,98 @@
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
/**
|
||||
* Annotation-based aspect to use in test build to enable mocking static methods
|
||||
* on JPA-annotated {@code @Entity} classes, as used by Roo for finders.
|
||||
* Annotation-based aspect to use in test builds to enable mocking of static methods
|
||||
* on JPA-annotated {@code @Entity} classes, as used by Spring Roo for so-called
|
||||
* <em>finder methods</em>.
|
||||
*
|
||||
* <p>Mocking will occur in the call stack of any method in a class (typically a test class)
|
||||
* that is annotated with the @MockStaticEntityMethods annotation.
|
||||
* <p>Mocking will occur within the call stack of any {@code public} method in a
|
||||
* class (typically a test class) that is annotated with {@code @MockStaticEntityMethods}.
|
||||
* Thus mocking is not limited to {@code @Test} methods. Furthermore, new mock
|
||||
* state will be created for the invocation of each such public method, even when
|
||||
* the method is invoked from another such public method.
|
||||
*
|
||||
* <p>Also provides static methods to simplify the programming model for
|
||||
* entering playback mode and setting expected return values.
|
||||
* <p>This aspect also provides static methods to simplify the programming model for
|
||||
* setting expectations and entering playback mode.
|
||||
*
|
||||
* <p>Usage:
|
||||
* <h3>Usage</h3>
|
||||
* <ol>
|
||||
* <li>Annotate a test class with @MockStaticEntityMethods.
|
||||
* <li>In each test method, AnnotationDrivenStaticEntityMockingControl will begin in recording mode.
|
||||
* Invoke static methods on Entity classes, with each recording-mode invocation
|
||||
* being followed by an invocation to the static expectReturn() or expectThrow()
|
||||
* method on AnnotationDrivenStaticEntityMockingControl.
|
||||
* <li>Invoke the static AnnotationDrivenStaticEntityMockingControl() method.
|
||||
* <li>Call the code you wish to test that uses the static methods. Verification will
|
||||
* occur automatically.
|
||||
* <li>Annotate a test class with {@code @MockStaticEntityMethods}.
|
||||
* <li>In each test method, the {@code AnnotationDrivenStaticEntityMockingControl}
|
||||
* will begin in <em>recording</em> mode.
|
||||
* <li>Invoke static methods on JPA-annotated {@code @Entity} classes, with each
|
||||
* recording-mode invocation being followed by an invocation of either
|
||||
* {@link #expectReturn(Object)} or {@link #expectThrow(Throwable)} on the
|
||||
* {@code AnnotationDrivenStaticEntityMockingControl}.
|
||||
* <li>Invoke the {@link #playback()} method.
|
||||
* <li>Call the code you wish to test that uses the static methods on the
|
||||
* JPA-annotated {@code @Entity} classes.
|
||||
* <li>Verification will occur automatically after the test method has executed
|
||||
* and returned. However, mock verification will not occur if the test method
|
||||
* throws an exception.
|
||||
* </ol>
|
||||
*
|
||||
* <h3>Programmatic Control of the Mock</h3>
|
||||
* <p>For scenarios where it would be convenient to programmatically <em>verify</em>
|
||||
* the recorded expectations or <em>reset</em> the state of the mock, consider
|
||||
* using combinations of {@link #verify()} and {@link #reset()}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Sam Brannen
|
||||
* @see MockStaticEntityMethods
|
||||
*/
|
||||
public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl {
|
||||
|
||||
/**
|
||||
* Stop recording mock calls and enter playback state
|
||||
* Expect the supplied {@link Object} to be returned by the previous static
|
||||
* method invocation.
|
||||
* @see #playback()
|
||||
*/
|
||||
public static void expectReturn(Object retVal) {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectReturnInternal(retVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect the supplied {@link Throwable} to be thrown by the previous static
|
||||
* method invocation.
|
||||
* @see #playback()
|
||||
*/
|
||||
public static void expectThrow(Throwable throwable) {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectThrowInternal(throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop recording mock expectations and enter <em>playback</em> mode.
|
||||
* @see #expectReturn(Object)
|
||||
* @see #expectThrow(Throwable)
|
||||
*/
|
||||
public static void playback() {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().playbackInternal();
|
||||
}
|
||||
|
||||
public static void expectReturn(Object retVal) {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectReturnInternal(retVal);
|
||||
/**
|
||||
* Verify that all expectations have been fulfilled.
|
||||
* @since 4.0.2
|
||||
* @see #reset()
|
||||
*/
|
||||
public static void verify() {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().verifyInternal();
|
||||
}
|
||||
|
||||
public static void expectThrow(Throwable throwable) {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectThrowInternal(throwable);
|
||||
/**
|
||||
* Reset the state of the mock and enter <em>recording</em> mode.
|
||||
* @since 4.0.2
|
||||
* @see #verify()
|
||||
*/
|
||||
public static void reset() {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().resetInternal();
|
||||
}
|
||||
|
||||
// Only matches directly annotated @Test methods, to allow methods in
|
||||
// @MockStatics classes to invoke each other without resetting the mocking environment
|
||||
// Apparently, the following pointcut was originally defined to only match
|
||||
// methods directly annotated with @Test (in order to allow methods in
|
||||
// @MockStaticEntityMethods classes to invoke each other without creating a
|
||||
// new mocking environment); however, this is no longer the case. The current
|
||||
// pointcut applies to all public methods in @MockStaticEntityMethods classes.
|
||||
protected pointcut mockStaticsTestMethod() : execution(public * (@MockStaticEntityMethods *).*(..));
|
||||
|
||||
protected pointcut methodToMock() : execution(public static * (@javax.persistence.Entity *).*(..));
|
||||
|
||||
+6
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,11 +22,13 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation to indicate a test class for whose @Test methods
|
||||
* static methods on Entity classes should be mocked. See
|
||||
* {@code AbstractMethodMockingControl}.
|
||||
* Annotation to indicate a test class for whose {@code @Test} methods
|
||||
* static methods on JPA-annotated {@code @Entity} classes should be mocked.
|
||||
*
|
||||
* <p>See {@link AnnotationDrivenStaticEntityMockingControl} for details.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -32,6 +32,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
||||
* @since 3.1
|
||||
* @see EnableAsync
|
||||
* @see org.springframework.scheduling.annotation.AsyncConfigurationSelector
|
||||
* @see org.springframework.scheduling.annotation.ProxyAsyncConfiguration
|
||||
*/
|
||||
@Configuration
|
||||
public class AspectJAsyncConfiguration extends AbstractAsyncConfiguration {
|
||||
|
||||
-147
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.expectReturn;
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.expectThrow;
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.playback;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/**
|
||||
* Test for static entity mocking framework.
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
@MockStaticEntityMethods
|
||||
@RunWith(JUnit4.class)
|
||||
public class AnnotationDrivenStaticEntityMockingControlTest {
|
||||
|
||||
@Test
|
||||
public void testNoArgIntReturn() {
|
||||
int expectedCount = 13;
|
||||
Person.countPeople();
|
||||
expectReturn(expectedCount);
|
||||
playback();
|
||||
assertEquals(expectedCount, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected=PersistenceException.class)
|
||||
public void testNoArgThrows() {
|
||||
Person.countPeople();
|
||||
expectThrow(new PersistenceException());
|
||||
playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodMatches() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLongSeriesOfCalls() {
|
||||
long id1 = 13;
|
||||
long id2 = 24;
|
||||
Person found1 = new Person();
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person found2 = new Person();
|
||||
Person.findPerson(id2);
|
||||
expectReturn(found2);
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person.countPeople();
|
||||
expectReturn(0);
|
||||
playback();
|
||||
|
||||
assertEquals(found1, Person.findPerson(id1));
|
||||
assertEquals(found2, Person.findPerson(id2));
|
||||
assertEquals(found1, Person.findPerson(id1));
|
||||
assertEquals(0, Person.countPeople());
|
||||
}
|
||||
|
||||
// Note delegation is used when tests are invalid and should fail, as otherwise
|
||||
// the failure will occur on the verify() method in the aspect after
|
||||
// this method returns, failing the test case
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
try {
|
||||
new Delegate().testArgMethodNoMatchExpectReturn();
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
new Delegate().testArgMethodNoMatchExpectThrow();
|
||||
}
|
||||
|
||||
private void called(Person found, long id) {
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReentrant() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
called(found, id);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testRejectUnexpectedCall() {
|
||||
new Delegate().rejectUnexpectedCall();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testFailTooFewCalls() {
|
||||
new Delegate().failTooFewCalls();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
// Test that verification check doesn't blow up if no replay() call happened
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverReplay() {
|
||||
new Delegate().doesntEverReplay();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverSetReturn() {
|
||||
new Delegate().doesntEverSetReturn();
|
||||
}
|
||||
}
|
||||
|
||||
+300
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.*;
|
||||
|
||||
/**
|
||||
* Tests for Spring's static entity mocking framework (i.e., @{@link MockStaticEntityMethods}
|
||||
* and {@link AnnotationDrivenStaticEntityMockingControl}).
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@MockStaticEntityMethods
|
||||
public class AnnotationDrivenStaticEntityMockingControlTests {
|
||||
|
||||
@Test
|
||||
public void noArgumentMethodInvocationReturnsInt() {
|
||||
int expectedCount = 13;
|
||||
Person.countPeople();
|
||||
expectReturn(expectedCount);
|
||||
playback();
|
||||
assertEquals(expectedCount, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected = PersistenceException.class)
|
||||
public void noArgumentMethodInvocationThrowsException() {
|
||||
Person.countPeople();
|
||||
expectThrow(new PersistenceException());
|
||||
playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodArgumentsMatch() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longSeriesOfCalls() {
|
||||
long id1 = 13;
|
||||
long id2 = 24;
|
||||
Person found1 = new Person();
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person found2 = new Person();
|
||||
Person.findPerson(id2);
|
||||
expectReturn(found2);
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person.countPeople();
|
||||
expectReturn(0);
|
||||
playback();
|
||||
|
||||
assertEquals(found1, Person.findPerson(id1));
|
||||
assertEquals(found2, Person.findPerson(id2));
|
||||
assertEquals(found1, Person.findPerson(id1));
|
||||
assertEquals(0, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void methodArgumentsDoNotMatchAndReturnsObject() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void methodArgumentsDoNotMatchAndThrowsException() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectThrow(new PersistenceException());
|
||||
playback();
|
||||
assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reentrantCallToPrivateMethod() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
privateMethod(found, id);
|
||||
}
|
||||
|
||||
private void privateMethod(Person found, long id) {
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reentrantCallToPublicMethod() {
|
||||
final Long ID = 13L;
|
||||
Person.findPerson(ID);
|
||||
expectReturn(new Person());
|
||||
playback();
|
||||
try {
|
||||
publicMethod();
|
||||
fail("Should have thrown an IllegalStateException");
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
String snippet = "Calls have been recorded, but playback state was never reached.";
|
||||
assertTrue("Exception message should contain [" + snippet + "]", e.getMessage().contains(snippet));
|
||||
}
|
||||
|
||||
// Now to keep the mock for "this" method happy:
|
||||
Person.findPerson(ID);
|
||||
}
|
||||
|
||||
public void publicMethod() {
|
||||
// At this point, since publicMethod() is a public method in a class
|
||||
// annotated with @MockStaticEntityMethods, the current mock state is
|
||||
// fresh. In other words, we are again in recording mode. As such, any
|
||||
// call to a mocked method will return null. See the implementation of
|
||||
// the <methodToMock() && cflowbelow(mockStaticsTestMethod())> around
|
||||
// advice in AbstractMethodMockingControl for details.
|
||||
assertNull(Person.findPerson(99L));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void unexpectedCall() {
|
||||
playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void tooFewCalls() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
Person.countPeople();
|
||||
expectReturn(25);
|
||||
playback();
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noExpectationsAndNoPlayback() {
|
||||
// Ensure that mock verification doesn't blow up if playback() was not invoked and
|
||||
// no expectations were set.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noExpectationsButWithPlayback() {
|
||||
// Ensure that mock verification doesn't blow up if playback() was invoked but no
|
||||
// expectations were set.
|
||||
playback();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void doesNotEnterPlaybackMode() {
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void doesNotSetExpectedReturnValue() {
|
||||
Person.countPeople();
|
||||
playback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently, the method mocking aspect will not verify the state of the
|
||||
* expectations within the mock if a test method throws an exception.
|
||||
*
|
||||
* <p>The reason is that the {@code mockStaticsTestMethod()} advice in
|
||||
* {@link AbstractMethodMockingControl} is declared as
|
||||
* {@code after() returning} instead of simply {@code after()}.
|
||||
*
|
||||
* <p>If the aforementioned advice is changed to a generic "after" advice,
|
||||
* this test method will fail with an {@link IllegalStateException} (thrown
|
||||
* by the mock aspect) instead of the {@link UnsupportedOperationException}
|
||||
* thrown by the test method itself.
|
||||
*/
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void mockVerificationDoesNotOccurIfTestFailsWithAnExpectedException() {
|
||||
Person.countPeople();
|
||||
playback();
|
||||
// We intentionally do not execute any of the recorded method invocations in order
|
||||
// to demonstrate that mock verification does not occur if an
|
||||
// exception is thrown.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resetMockWithoutVerficationAndStartOverWithoutRedeclaringExpectations() {
|
||||
final Long ID = 13L;
|
||||
Person.findPerson(ID);
|
||||
expectReturn(new Person());
|
||||
|
||||
reset();
|
||||
|
||||
Person.findPerson(ID);
|
||||
// Omit expectation.
|
||||
playback();
|
||||
|
||||
try {
|
||||
Person.findPerson(ID);
|
||||
fail("Should have thrown an IllegalStateException");
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
String snippet = "Behavior of Call with signature";
|
||||
assertTrue("Exception message should contain [" + snippet + "]", e.getMessage().contains(snippet));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resetMockWithoutVerificationAndStartOver() {
|
||||
final Long ID = 13L;
|
||||
Person found = new Person();
|
||||
Person.findPerson(ID);
|
||||
expectReturn(found);
|
||||
|
||||
reset();
|
||||
|
||||
// Intentionally use a different ID:
|
||||
final long ID_2 = ID + 1;
|
||||
Person.findPerson(ID_2);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
|
||||
assertEquals(found, Person.findPerson(ID_2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyResetAndStartOver() {
|
||||
final Long ID_1 = 13L;
|
||||
Person found1 = new Person();
|
||||
Person.findPerson(ID_1);
|
||||
expectReturn(found1);
|
||||
playback();
|
||||
|
||||
assertEquals(found1, Person.findPerson(ID_1));
|
||||
verify();
|
||||
reset();
|
||||
|
||||
// Intentionally use a different ID:
|
||||
final long ID_2 = ID_1 + 1;
|
||||
Person found2 = new Person();
|
||||
Person.findPerson(ID_2);
|
||||
expectReturn(found2);
|
||||
playback();
|
||||
|
||||
assertEquals(found2, Person.findPerson(ID_2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyWithTooFewCalls() {
|
||||
final Long ID = 13L;
|
||||
Person found = new Person();
|
||||
Person.findPerson(ID);
|
||||
expectReturn(found);
|
||||
Person.findPerson(ID);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
|
||||
assertEquals(found, Person.findPerson(ID));
|
||||
|
||||
try {
|
||||
verify();
|
||||
fail("Should have thrown an IllegalStateException");
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
assertEquals("Expected 2 calls, but received 1", e.getMessage());
|
||||
// Since verify() failed, we need to manually reset so that the test method
|
||||
// does not fail.
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl;
|
||||
import org.springframework.mock.staticmock.MockStaticEntityMethods;
|
||||
|
||||
//Used because verification failures occur after method returns,
|
||||
//so we can't test for them in the test case itself
|
||||
@MockStaticEntityMethods
|
||||
@Ignore // This isn't meant for direct testing; rather it is driven from AnnotationDrivenStaticEntityMockingControl
|
||||
public class Delegate {
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failTooFewCalls() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverReplay() {
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverSetReturn() {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectUnexpectedCall() {
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected=RemoteException.class)
|
||||
public void testVerificationFailsEvenWhenTestFailsInExpectedManner() throws RemoteException {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
// No calls to allow verification failure
|
||||
throw new RemoteException();
|
||||
}
|
||||
}
|
||||
+31
-23
@@ -56,10 +56,11 @@ import org.springframework.core.io.support.EncodedResource;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
|
||||
/**
|
||||
* A Groovy-based reader for Spring bean definitions: Like a Groovy builder,
|
||||
* A Groovy-based reader for Spring bean definitions: like a Groovy builder,
|
||||
* but more of a DSL for Spring configuration. Allows syntax like:
|
||||
*
|
||||
* <pre>import org.hibernate.SessionFactory
|
||||
* <pre class="code">
|
||||
* import org.hibernate.SessionFactory
|
||||
* import org.apache.commons.dbcp.BasicDataSource
|
||||
*
|
||||
* def reader = new GroovyBeanDefinitionReader(myApplicationContext)
|
||||
@@ -81,11 +82,12 @@ import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>You can also load resources containing beans defined as a Groovy script using
|
||||
* <p>You can also load resources containing beans defined in a Groovy script using
|
||||
* either the {@link #loadBeanDefinitions(org.springframework.core.io.Resource...)}
|
||||
* or {@link #loadBeanDefinitions(String...)} method, with a script looking as follows:
|
||||
*
|
||||
* <pre>import org.hibernate.SessionFactory
|
||||
* <pre class="code">
|
||||
* import org.hibernate.SessionFactory
|
||||
* import org.apache.commons.dbcp.BasicDataSource
|
||||
*
|
||||
* beans {
|
||||
@@ -257,10 +259,10 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines an inner bean definition
|
||||
* @param type The bean type
|
||||
* @param args The constructors arguments and closure configurer
|
||||
* @return The bean definition
|
||||
* Define an inner bean definition.
|
||||
* @param type the bean type
|
||||
* @param args the constructors arguments and closure configurer
|
||||
* @return the bean definition
|
||||
*/
|
||||
public AbstractBeanDefinition bean(Class<?> type, Object...args) {
|
||||
GroovyBeanDefinitionWrapper current = this.currentBeanDefinition;
|
||||
@@ -292,7 +294,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines an Spring namespace definition to use.
|
||||
* Define a Spring namespace definition to use.
|
||||
* @param definition the namespace definition
|
||||
*/
|
||||
public void xmlns(Map<String, String> definition) {
|
||||
@@ -314,7 +316,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports Spring bean definitions from either XML or Groovy sources into the current bean builder instance.
|
||||
* Import Spring bean definitions from either XML or Groovy sources into the
|
||||
* current bean builder instance.
|
||||
* @param resourcePattern the resource pattern
|
||||
*/
|
||||
public void importBeans(String resourcePattern) throws IOException {
|
||||
@@ -336,7 +339,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
|
||||
/**
|
||||
* This method overrides method invocation to create beans for each method name that
|
||||
* takes a class argument
|
||||
* takes a class argument.
|
||||
*/
|
||||
public Object invokeMethod(String name, Object arg) {
|
||||
Object[] args = (Object[])arg;
|
||||
@@ -411,7 +414,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
/**
|
||||
* When an methods argument is only a closure it is a set of bean definitions.
|
||||
* When a method argument is only a closure it is a set of bean definitions.
|
||||
* @param callable the closure argument
|
||||
* @return this GroovyBeanDefinitionReader instance
|
||||
*/
|
||||
@@ -528,7 +531,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether there are any {@link RuntimeBeanReference} inside the Map
|
||||
* Checks whether there are any {@link RuntimeBeanReference}s inside the Map
|
||||
* and converts it to a ManagedMap if necessary.
|
||||
* @param map the original Map
|
||||
* @return either the original map or a managed copy of it
|
||||
@@ -550,8 +553,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether there are any {@link RuntimeBeanReference} inside the Lis
|
||||
* and converts it to a ManagedList if necessary.
|
||||
* Checks whether there are any {@link RuntimeBeanReference}s inside the List
|
||||
* and converts it to a ManagedList if necessary.
|
||||
* @param list the original List
|
||||
* @return either the original list or a managed copy of it
|
||||
*/
|
||||
@@ -612,10 +615,14 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
/**
|
||||
* This method overrides property retrieval in the scope of the GroovyBeanDefinitionReader to either:
|
||||
* a) Retrieve a variable from the bean builder's binding if it exists
|
||||
* b) Retrieve a RuntimeBeanReference for a specific bean if it exists
|
||||
* c) Otherwise just delegate to MetaClass.getProperty which will resolve properties from the GroovyBeanDefinitionReader itself
|
||||
* This method overrides property retrieval in the scope of the
|
||||
* GroovyBeanDefinitionReader to either:
|
||||
* <ul>
|
||||
* <li>Retrieve a variable from the bean builder's binding if it exists
|
||||
* <li>Retrieve a RuntimeBeanReference for a specific bean if it exists
|
||||
* <li>Otherwise just delegate to MetaClass.getProperty which will resolve
|
||||
* properties from the GroovyBeanDefinitionReader itself
|
||||
* </ul>
|
||||
*/
|
||||
public Object getProperty(String name) {
|
||||
Binding binding = getBinding();
|
||||
@@ -678,9 +685,10 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
|
||||
|
||||
/**
|
||||
* This class is used to defer the adding of a property to a bean definition until later
|
||||
* This is for a case where you assign a property to a list that may not contain bean references at
|
||||
* that point of assignment, but may later hence it would need to be managed
|
||||
* This class is used to defer the adding of a property to a bean definition
|
||||
* until later. This is for a case where you assign a property to a list that
|
||||
* may not contain bean references at that point of assignment, but may later;
|
||||
* hence, it would need to be managed.
|
||||
*/
|
||||
private static class DeferredProperty {
|
||||
|
||||
@@ -703,7 +711,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
|
||||
|
||||
/**
|
||||
* A RuntimeBeanReference that takes care of adding new properties to runtime references
|
||||
* A RuntimeBeanReference that takes care of adding new properties to runtime references.
|
||||
*/
|
||||
private class GroovyRuntimeBeanReference extends RuntimeBeanReference implements GroovyObject {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -20,33 +20,36 @@ import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
|
||||
/**
|
||||
* Strategy for creating {@link BeanInfo} instances.
|
||||
* Strategy interface for creating {@link BeanInfo} instances for Spring beans.
|
||||
* Can be used to plug in custom bean property resolution strategies (e.g. for other
|
||||
* languages on the JVM) or more efficient {@link BeanInfo} retrieval algorithms.
|
||||
*
|
||||
* <p>BeanInfoFactories are are instantiated by the {@link CachedIntrospectionResults},
|
||||
* by using the {@link org.springframework.core.io.support.SpringFactoriesLoader} utility
|
||||
* class.
|
||||
* by using the {@link org.springframework.core.io.support.SpringFactoriesLoader}
|
||||
* utility class.
|
||||
*
|
||||
* When a {@link BeanInfo} is to be created, the {@code CachedIntrospectionResults}
|
||||
* will iterate through the discovered factories, calling {@link
|
||||
* #getBeanInfo(Class)} on each one. If {@code null} is returned, the next factory will
|
||||
* be queried. If none of the factories support the class, an standard {@link BeanInfo}
|
||||
* is created as a default.
|
||||
* will iterate through the discovered factories, calling {@link #getBeanInfo(Class)}
|
||||
* on each one. If {@code null} is returned, the next factory will be queried.
|
||||
* If none of the factories support the class, a standard {@link BeanInfo} will be
|
||||
* created as a default.
|
||||
*
|
||||
* <p>Note that the {@link org.springframework.core.io.support.SpringFactoriesLoader}
|
||||
* sorts the {@code BeanInfoFactory} instances by
|
||||
* {@link org.springframework.core.annotation.Order @Order}, so that ones with
|
||||
* a higher precedence come first.
|
||||
* {@link org.springframework.core.annotation.Order @Order}, so that ones with a
|
||||
* higher precedence come first.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.2
|
||||
* @see CachedIntrospectionResults
|
||||
* @see org.springframework.core.io.support.SpringFactoriesLoader
|
||||
*/
|
||||
public interface BeanInfoFactory {
|
||||
|
||||
/**
|
||||
* Returns the bean info for the given class, if supported.
|
||||
*
|
||||
* Return the bean info for the given class, if supported.
|
||||
* @param beanClass the bean class
|
||||
* @return the bean info, or {@code null} if not the given class is not supported
|
||||
* @return the BeanInfo, or {@code null} if the given class is not supported
|
||||
* @throws IntrospectionException in case of exceptions
|
||||
*/
|
||||
BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException;
|
||||
|
||||
@@ -600,7 +600,7 @@ public abstract class BeanUtils {
|
||||
if (sourcePd != null) {
|
||||
Method readMethod = sourcePd.getReadMethod();
|
||||
if (readMethod != null &&
|
||||
writeMethod.getParameterTypes()[0].isAssignableFrom(readMethod.getReturnType())) {
|
||||
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
|
||||
try {
|
||||
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
|
||||
readMethod.setAccessible(true);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -79,11 +79,13 @@ public interface BeanWrapper extends ConfigurablePropertyAccessor {
|
||||
PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;
|
||||
|
||||
/**
|
||||
* Set whether this BeanWrapper should attempt to "auto-grow" a nested path that contains a null value.
|
||||
* <p>If "true", a null path location will be populated with a default object value and traversed
|
||||
* instead of resulting in a {@link NullValueInNestedPathException}. Turning this flag on also
|
||||
* enables auto-growth of collection elements when accessing an out-of-bounds index.
|
||||
* <p>Default is "false" on a plain BeanWrapper.
|
||||
* Set whether this BeanWrapper should attempt to "auto-grow" a
|
||||
* nested path that contains a {@code null} value.
|
||||
* <p>If {@code true}, a {@code null} path location will be populated
|
||||
* with a default object value and traversed instead of resulting in a
|
||||
* {@link NullValueInNestedPathException}. Turning this flag on also enables
|
||||
* auto-growth of collection elements when accessing an out-of-bounds index.
|
||||
* <p>Default is {@code false} on a plain BeanWrapper.
|
||||
*/
|
||||
void setAutoGrowNestedPaths(boolean autoGrowNestedPaths);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,6 +37,7 @@ import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.convert.ConversionException;
|
||||
@@ -492,21 +493,22 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
public Object convertForProperty(Object value, String propertyName) throws TypeMismatchException {
|
||||
CachedIntrospectionResults cachedIntrospectionResults = getCachedIntrospectionResults();
|
||||
PropertyDescriptor pd = cachedIntrospectionResults.getPropertyDescriptor(propertyName);
|
||||
TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd);
|
||||
if (pd == null) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"No property '" + propertyName + "' found");
|
||||
}
|
||||
TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd);
|
||||
if (td == null) {
|
||||
td = new TypeDescriptor(property(pd));
|
||||
cachedIntrospectionResults.putTypeDescriptor(pd, td);
|
||||
cachedIntrospectionResults.addTypeDescriptor(pd, td);
|
||||
}
|
||||
return convertForProperty(propertyName, null, value, pd, td);
|
||||
return convertForProperty(propertyName, null, value, td);
|
||||
}
|
||||
|
||||
private Object convertForProperty(String propertyName, Object oldValue, Object newValue, PropertyDescriptor pd, TypeDescriptor td)
|
||||
private Object convertForProperty(String propertyName, Object oldValue, Object newValue, TypeDescriptor td)
|
||||
throws TypeMismatchException {
|
||||
return convertIfNecessary(propertyName, oldValue, newValue, pd.getPropertyType(), td);
|
||||
|
||||
return convertIfNecessary(propertyName, oldValue, newValue, td.getType(), td);
|
||||
}
|
||||
|
||||
private Property property(PropertyDescriptor pd) {
|
||||
@@ -811,7 +813,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
Class<?> mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(pd.getReadMethod(), i + 1);
|
||||
// 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 = mapKeyType != null ? TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class);
|
||||
TypeDescriptor typeDescriptor = (mapKeyType != null ?
|
||||
TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class));
|
||||
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor);
|
||||
value = map.get(convertedMapKey);
|
||||
}
|
||||
@@ -868,8 +871,9 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
}
|
||||
|
||||
private void growCollectionIfNecessary(Collection<Object> collection, int index,
|
||||
String name, PropertyDescriptor pd, int nestingLevel) {
|
||||
private void growCollectionIfNecessary(Collection<Object> collection, int index, String name,
|
||||
PropertyDescriptor pd, int nestingLevel) {
|
||||
|
||||
if (!this.autoGrowNestedPaths) {
|
||||
return;
|
||||
}
|
||||
@@ -1112,7 +1116,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
}
|
||||
}
|
||||
valueToApply = convertForProperty(propertyName, oldValue, originalValue, pd, new TypeDescriptor(property(pd)));
|
||||
valueToApply = convertForProperty(
|
||||
propertyName, oldValue, originalValue, new TypeDescriptor(property(pd)));
|
||||
}
|
||||
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
|
||||
}
|
||||
|
||||
+51
-24
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,6 @@ import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -30,10 +29,12 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.SpringProperties;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -52,6 +53,18 @@ import org.springframework.util.StringUtils;
|
||||
* implements the factory design pattern, using a private constructor and
|
||||
* a static {@link #forClass(Class)} factory method to obtain instances.
|
||||
*
|
||||
* <p>Note that for caching to work effectively, some preconditions need to be met:
|
||||
* Prefer an arrangement where the Spring jars live in the same ClassLoader as the
|
||||
* application classes, which allows for clean caching along with the application's
|
||||
* lifecycle in any case. For a web application, consider declaring a local
|
||||
* {@link org.springframework.web.util.IntrospectorCleanupListener} in {@code web.xml}
|
||||
* in case of a multi-ClassLoader layout, which will allow for effective caching as well.
|
||||
*
|
||||
* <p>In case of a non-clean ClassLoader arrangement without a cleanup listener having
|
||||
* been set up, this class will fall back to a weak-reference-based caching model that
|
||||
* recreates much-requested entries every time the garbage collector removed them. In
|
||||
* such a scenario, consider the {@link #IGNORE_BEANINFO_PROPERTY_NAME} system property.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 05 May 2001
|
||||
@@ -61,11 +74,34 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class CachedIntrospectionResults {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(CachedIntrospectionResults.class);
|
||||
/**
|
||||
* System property that instructs Spring to use the {@link Introspector#IGNORE_ALL_BEANINFO}
|
||||
* mode when calling the JavaBeans {@link Introspector}: "spring.beaninfo.ignore", with a
|
||||
* value of "true" skipping the search for {@code BeanInfo} classes (typically for scenarios
|
||||
* where no such classes are being defined for beans in the application in the first place).
|
||||
* <p>The default is "false", considering all {@code BeanInfo} metadata classes, like for
|
||||
* standard {@link Introspector#getBeanInfo(Class)} calls. Consider switching this flag to
|
||||
* "true" if you experience repeated ClassLoader access for non-existing {@code BeanInfo}
|
||||
* classes, in case such access is expensive on startup or on lazy loading.
|
||||
* <p>Note that such an effect may also indicate a scenario where caching doesn't work
|
||||
* effectively: Prefer an arrangement where the Spring jars live in the same ClassLoader
|
||||
* as the application classes, which allows for clean caching along with the application's
|
||||
* lifecycle in any case. For a web application, consider declaring a local
|
||||
* {@link org.springframework.web.util.IntrospectorCleanupListener} in {@code web.xml}
|
||||
* in case of a multi-ClassLoader layout, which will allow for effective caching as well.
|
||||
* @see Introspector#getBeanInfo(Class, int)
|
||||
*/
|
||||
public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore";
|
||||
|
||||
|
||||
private static final boolean shouldIntrospectorIgnoreBeaninfoClasses =
|
||||
SpringProperties.getFlag(IGNORE_BEANINFO_PROPERTY_NAME);
|
||||
|
||||
/** Stores the BeanInfoFactory instances */
|
||||
private static List<BeanInfoFactory> beanInfoFactories =
|
||||
SpringFactoriesLoader.loadFactories(BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader());
|
||||
private static List<BeanInfoFactory> beanInfoFactories = SpringFactoriesLoader.loadFactories(
|
||||
BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader());
|
||||
|
||||
private static final Log logger = LogFactory.getLog(CachedIntrospectionResults.class);
|
||||
|
||||
/**
|
||||
* Set of ClassLoaders that this CachedIntrospectionResults class will always
|
||||
@@ -181,8 +217,8 @@ public class CachedIntrospectionResults {
|
||||
synchronized (acceptedClassLoaders) {
|
||||
acceptedLoaderArray = acceptedClassLoaders.toArray(new ClassLoader[acceptedClassLoaders.size()]);
|
||||
}
|
||||
for (ClassLoader registeredLoader : acceptedLoaderArray) {
|
||||
if (isUnderneathClassLoader(classLoader, registeredLoader)) {
|
||||
for (ClassLoader acceptedLoader : acceptedLoaderArray) {
|
||||
if (isUnderneathClassLoader(classLoader, acceptedLoader)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -243,21 +279,12 @@ public class CachedIntrospectionResults {
|
||||
}
|
||||
if (beanInfo == null) {
|
||||
// If none of the factories supported the class, fall back to the default
|
||||
beanInfo = Introspector.getBeanInfo(beanClass);
|
||||
beanInfo = (shouldIntrospectorIgnoreBeaninfoClasses ?
|
||||
Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO) :
|
||||
Introspector.getBeanInfo(beanClass));
|
||||
}
|
||||
this.beanInfo = beanInfo;
|
||||
|
||||
// Immediately remove class from Introspector cache, to allow for proper
|
||||
// garbage collection on class loader shutdown - we cache it here anyway,
|
||||
// in a GC-friendly manner. In contrast to CachedIntrospectionResults,
|
||||
// Introspector does not use WeakReferences as values of its WeakHashMap!
|
||||
Class<?> classToFlush = beanClass;
|
||||
do {
|
||||
Introspector.flushFromCaches(classToFlush);
|
||||
classToFlush = classToFlush.getSuperclass();
|
||||
}
|
||||
while (classToFlush != null);
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Caching PropertyDescriptors for class [" + beanClass.getName() + "]");
|
||||
}
|
||||
@@ -281,7 +308,7 @@ public class CachedIntrospectionResults {
|
||||
this.propertyDescriptorCache.put(pd.getName(), pd);
|
||||
}
|
||||
|
||||
this.typeDescriptorCache = new HashMap<PropertyDescriptor, TypeDescriptor>();
|
||||
this.typeDescriptorCache = new ConcurrentHashMap<PropertyDescriptor, TypeDescriptor>();
|
||||
}
|
||||
catch (IntrospectionException ex) {
|
||||
throw new FatalBeanException("Failed to obtain BeanInfo for class [" + beanClass.getName() + "]", ex);
|
||||
@@ -330,12 +357,12 @@ public class CachedIntrospectionResults {
|
||||
}
|
||||
}
|
||||
|
||||
void addTypeDescriptor(PropertyDescriptor pd, TypeDescriptor td) {
|
||||
this.typeDescriptorCache.put(pd, td);
|
||||
}
|
||||
|
||||
TypeDescriptor getTypeDescriptor(PropertyDescriptor pd) {
|
||||
return this.typeDescriptorCache.get(pd);
|
||||
}
|
||||
|
||||
void putTypeDescriptor(PropertyDescriptor pd, TypeDescriptor td) {
|
||||
this.typeDescriptorCache.put(pd, td);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -25,8 +25,8 @@ import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* {@link BeanInfoFactory} implementation that evaluates whether bean classes have
|
||||
* "non-standard" JavaBeans setter methods and are thus candidates for introspection by
|
||||
* Spring's {@link ExtendedBeanInfo}.
|
||||
* "non-standard" JavaBeans setter methods and are thus candidates for introspection
|
||||
* by Spring's (package-visible) {@code ExtendedBeanInfo} implementation.
|
||||
*
|
||||
* <p>Ordered at {@link Ordered#LOWEST_PRECEDENCE} to allow other user-defined
|
||||
* {@link BeanInfoFactory} types to take precedence.
|
||||
@@ -34,21 +34,21 @@ import org.springframework.core.Ordered;
|
||||
* @author Chris Beams
|
||||
* @since 3.2
|
||||
* @see BeanInfoFactory
|
||||
* @see CachedIntrospectionResults
|
||||
*/
|
||||
public class ExtendedBeanInfoFactory implements Ordered, BeanInfoFactory {
|
||||
public class ExtendedBeanInfoFactory implements BeanInfoFactory, Ordered {
|
||||
|
||||
/**
|
||||
* Return a new {@link ExtendedBeanInfo} for the given bean class.
|
||||
* Return an {@link ExtendedBeanInfo} for the given bean class, if applicable.
|
||||
*/
|
||||
@Override
|
||||
public BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException {
|
||||
return supports(beanClass) ?
|
||||
new ExtendedBeanInfo(Introspector.getBeanInfo(beanClass)) : null;
|
||||
return (supports(beanClass) ? new ExtendedBeanInfo(Introspector.getBeanInfo(beanClass)) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given bean class declares or inherits any non-void returning
|
||||
* JavaBeans or <em>indexed property</em> setter methods.
|
||||
* Return whether the given bean class declares or inherits any non-void
|
||||
* returning bean property or indexed property setter methods.
|
||||
*/
|
||||
private boolean supports(Class<?> beanClass) {
|
||||
for (Method method : beanClass.getMethods()) {
|
||||
|
||||
+2
-2
@@ -317,10 +317,10 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
// Fall back to class name as cache key, for backwards compatibility with custom callers.
|
||||
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
|
||||
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
|
||||
if (metadata == null) {
|
||||
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
|
||||
synchronized (this.injectionMetadataCache) {
|
||||
metadata = this.injectionMetadataCache.get(cacheKey);
|
||||
if (metadata == null) {
|
||||
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
|
||||
metadata = buildAutowiringMetadata(clazz);
|
||||
this.injectionMetadataCache.put(cacheKey, metadata);
|
||||
}
|
||||
|
||||
+5
@@ -90,6 +90,11 @@ public class InjectionMetadata {
|
||||
}
|
||||
|
||||
|
||||
public static boolean needsRefresh(InjectionMetadata metadata, Class<?> clazz) {
|
||||
return (metadata == null || !metadata.targetClass.equals(clazz));
|
||||
}
|
||||
|
||||
|
||||
public static abstract class InjectedElement {
|
||||
|
||||
protected final Member member;
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -208,7 +208,7 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi
|
||||
visitor.visitBeanDefinition(bd);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage());
|
||||
throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -21,6 +21,8 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.core.Constants;
|
||||
import org.springframework.core.SpringProperties;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
import org.springframework.util.PropertyPlaceholderHelper;
|
||||
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
@@ -82,7 +84,8 @@ public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport
|
||||
|
||||
private int systemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK;
|
||||
|
||||
private boolean searchSystemEnvironment = true;
|
||||
private boolean searchSystemEnvironment =
|
||||
!SpringProperties.getFlag(AbstractEnvironment.IGNORE_GETENV_PROPERTY_NAME);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -1412,7 +1412,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
MutablePropertyValues mpvs = null;
|
||||
List<PropertyValue> original;
|
||||
|
||||
if (System.getSecurityManager()!= null) {
|
||||
if (System.getSecurityManager() != null) {
|
||||
if (bw instanceof BeanWrapperImpl) {
|
||||
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
|
||||
}
|
||||
@@ -1709,7 +1709,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
|
||||
|
||||
/**
|
||||
* Special DependencyDescriptor variant for autowire="byType".
|
||||
* Special DependencyDescriptor variant for Spring's good old autowire="byType" mode.
|
||||
* Always optional; never considering the parameter name for choosing a primary candidate.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -645,6 +645,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
/**
|
||||
* Specify whether to allow access to non-public constructors and methods,
|
||||
* for the case of externalized metadata pointing to those.
|
||||
* The default is {@code true}; switch this to {@false} for public access only.
|
||||
* <p>This applies to constructor resolution, factory method resolution,
|
||||
* and also init/destroy methods. Bean property accessors have to be public
|
||||
* in any case and are not affected by this setting.
|
||||
@@ -666,7 +667,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
/**
|
||||
* Specify whether to resolve constructors in lenient mode ({@code true},
|
||||
* which is the default) or to switch to strict resolution (throwing an exception
|
||||
* in case of ambigious constructors that all match when converting the arguments,
|
||||
* in case of ambiguous constructors that all match when converting the arguments,
|
||||
* whereas lenient mode would use the one with the 'closest' type matches).
|
||||
*/
|
||||
public void setLenientConstructorResolution(boolean lenientConstructorResolution) {
|
||||
|
||||
+157
-101
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,22 +22,28 @@ import java.lang.reflect.Method;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeanInstantiationException;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
|
||||
import org.springframework.cglib.core.SpringNamingPolicy;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.CallbackFilter;
|
||||
import org.springframework.cglib.proxy.Enhancer;
|
||||
import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.cglib.proxy.MethodInterceptor;
|
||||
import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.cglib.proxy.NoOp;
|
||||
|
||||
/**
|
||||
* Default object instantiation strategy for use in BeanFactories.
|
||||
* Uses CGLIB to generate subclasses dynamically if methods need to be
|
||||
* overridden by the container, to implement Method Injection.
|
||||
*
|
||||
* <p>Uses CGLIB to generate subclasses dynamically if methods need to be
|
||||
* overridden by the container to implement <em>Method Injection</em>.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 1.1
|
||||
*/
|
||||
public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy {
|
||||
@@ -50,30 +56,29 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
|
||||
/**
|
||||
* Index in the CGLIB callback array for a method that should
|
||||
* be overridden to provide method lookup.
|
||||
* be overridden to provide <em>method lookup</em>.
|
||||
*/
|
||||
private static final int LOOKUP_OVERRIDE = 1;
|
||||
|
||||
/**
|
||||
* Index in the CGLIB callback array for a method that should
|
||||
* be overridden using generic Methodreplacer functionality.
|
||||
* be overridden using generic <em>method replacer</em> functionality.
|
||||
*/
|
||||
private static final int METHOD_REPLACER = 2;
|
||||
|
||||
|
||||
@Override
|
||||
protected Object instantiateWithMethodInjection(
|
||||
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
|
||||
protected Object instantiateWithMethodInjection(RootBeanDefinition beanDefinition, String beanName,
|
||||
BeanFactory owner) {
|
||||
|
||||
// Must generate CGLIB subclass.
|
||||
return new CglibSubclassCreator(beanDefinition, owner).instantiate(null, null);
|
||||
return instantiateWithMethodInjection(beanDefinition, beanName, owner, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object instantiateWithMethodInjection(
|
||||
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
|
||||
Constructor<?> ctor, Object[] args) {
|
||||
protected Object instantiateWithMethodInjection(RootBeanDefinition beanDefinition, String beanName,
|
||||
BeanFactory owner, Constructor<?> ctor, Object[] args) {
|
||||
|
||||
// Must generate CGLIB subclass.
|
||||
return new CglibSubclassCreator(beanDefinition, owner).instantiate(ctor, args);
|
||||
}
|
||||
|
||||
@@ -84,123 +89,174 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
*/
|
||||
private static class CglibSubclassCreator {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(CglibSubclassCreator.class);
|
||||
private static final Class<?>[] CALLBACK_TYPES = new Class<?>[] { NoOp.class,
|
||||
LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class };
|
||||
|
||||
private final RootBeanDefinition beanDefinition;
|
||||
|
||||
private final BeanFactory owner;
|
||||
|
||||
public CglibSubclassCreator(RootBeanDefinition beanDefinition, BeanFactory owner) {
|
||||
|
||||
CglibSubclassCreator(RootBeanDefinition beanDefinition, BeanFactory owner) {
|
||||
this.beanDefinition = beanDefinition;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of a dynamically generated subclasses implementing the
|
||||
* Create a new instance of a dynamically generated subclass implementing the
|
||||
* required lookups.
|
||||
* @param ctor constructor to use. If this is {@code null}, use the
|
||||
* no-arg constructor (no parameterization, or Setter Injection)
|
||||
* @param args arguments to use for the constructor.
|
||||
* Ignored if the ctor parameter is {@code null}.
|
||||
* @return new instance of the dynamically generated class
|
||||
* Ignored if the {@code ctor} parameter is {@code null}.
|
||||
* @return new instance of the dynamically generated subclass
|
||||
*/
|
||||
public Object instantiate(Constructor<?> ctor, Object[] args) {
|
||||
Object instantiate(Constructor<?> ctor, Object[] args) {
|
||||
Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
|
||||
|
||||
Object instance;
|
||||
if (ctor == null) {
|
||||
instance = BeanUtils.instantiate(subclass);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
|
||||
instance = enhancedSubclassConstructor.newInstance(args);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new BeanInstantiationException(this.beanDefinition.getBeanClass(), String.format(
|
||||
"Failed to invoke construcor for CGLIB enhanced subclass [%s]", subclass.getName()), e);
|
||||
}
|
||||
}
|
||||
|
||||
// SPR-10785: set callbacks directly on the instance instead of in the
|
||||
// enhanced class (via the Enhancer) in order to avoid memory leaks.
|
||||
Factory factory = (Factory) instance;
|
||||
factory.setCallbacks(new Callback[] { NoOp.INSTANCE,//
|
||||
new LookupOverrideMethodInterceptor(beanDefinition, owner),//
|
||||
new ReplaceOverrideMethodInterceptor(beanDefinition, owner) });
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an enhanced subclass of the bean class for the provided bean
|
||||
* definition, using CGLIB.
|
||||
*/
|
||||
private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
|
||||
Enhancer enhancer = new Enhancer();
|
||||
enhancer.setSuperclass(this.beanDefinition.getBeanClass());
|
||||
enhancer.setCallbackFilter(new CallbackFilterImpl());
|
||||
enhancer.setCallbacks(new Callback[] {
|
||||
NoOp.INSTANCE,
|
||||
new LookupOverrideMethodInterceptor(),
|
||||
new ReplaceOverrideMethodInterceptor()
|
||||
});
|
||||
enhancer.setSuperclass(beanDefinition.getBeanClass());
|
||||
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
||||
enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
|
||||
enhancer.setCallbackTypes(CALLBACK_TYPES);
|
||||
return enhancer.createClass();
|
||||
}
|
||||
}
|
||||
|
||||
return (ctor == null) ?
|
||||
enhancer.create() :
|
||||
enhancer.create(ctor.getParameterTypes(), args);
|
||||
/**
|
||||
* Class providing hashCode and equals methods required by CGLIB to
|
||||
* ensure that CGLIB doesn't generate a distinct class per bean.
|
||||
* Identity is based on class and bean definition.
|
||||
*/
|
||||
private static class CglibIdentitySupport {
|
||||
|
||||
private final RootBeanDefinition beanDefinition;
|
||||
|
||||
|
||||
CglibIdentitySupport(RootBeanDefinition beanDefinition) {
|
||||
this.beanDefinition = beanDefinition;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class providing hashCode and equals methods required by CGLIB to
|
||||
* ensure that CGLIB doesn't generate a distinct class per bean.
|
||||
* Identity is based on class and bean definition.
|
||||
*/
|
||||
private class CglibIdentitySupport {
|
||||
|
||||
/**
|
||||
* Exposed for equals method to allow access to enclosing class field
|
||||
*/
|
||||
protected RootBeanDefinition getBeanDefinition() {
|
||||
return beanDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return (other.getClass().equals(getClass()) &&
|
||||
((CglibIdentitySupport) other).getBeanDefinition().equals(beanDefinition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return beanDefinition.hashCode();
|
||||
}
|
||||
RootBeanDefinition getBeanDefinition() {
|
||||
return this.beanDefinition;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CGLIB MethodInterceptor to override methods, replacing them with an
|
||||
* implementation that returns a bean looked up in the container.
|
||||
*/
|
||||
private class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
|
||||
|
||||
@Override
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
|
||||
// Cast is safe, as CallbackFilter filters are used selectively.
|
||||
LookupOverride lo = (LookupOverride) beanDefinition.getMethodOverrides().getOverride(method);
|
||||
return owner.getBean(lo.getBeanName());
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other.getClass().equals(this.getClass())
|
||||
&& ((CglibIdentitySupport) other).getBeanDefinition().equals(this.getBeanDefinition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.beanDefinition.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CGLIB MethodInterceptor to override methods, replacing them with a call
|
||||
* to a generic MethodReplacer.
|
||||
*/
|
||||
private class ReplaceOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
|
||||
/**
|
||||
* CGLIB callback for filtering method interception behavior.
|
||||
*/
|
||||
private static class MethodOverrideCallbackFilter extends CglibIdentitySupport implements CallbackFilter {
|
||||
|
||||
@Override
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
|
||||
ReplaceOverride ro = (ReplaceOverride) beanDefinition.getMethodOverrides().getOverride(method);
|
||||
// TODO could cache if a singleton for minor performance optimization
|
||||
MethodReplacer mr = (MethodReplacer) owner.getBean(ro.getMethodReplacerBeanName());
|
||||
return mr.reimplement(obj, method, args);
|
||||
}
|
||||
private static final Log logger = LogFactory.getLog(MethodOverrideCallbackFilter.class);
|
||||
|
||||
|
||||
MethodOverrideCallbackFilter(RootBeanDefinition beanDefinition) {
|
||||
super(beanDefinition);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CGLIB object to filter method interception behavior.
|
||||
*/
|
||||
private class CallbackFilterImpl extends CglibIdentitySupport implements CallbackFilter {
|
||||
|
||||
@Override
|
||||
public int accept(Method method) {
|
||||
MethodOverride methodOverride = beanDefinition.getMethodOverrides().getOverride(method);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Override for '" + method.getName() + "' is [" + methodOverride + "]");
|
||||
}
|
||||
if (methodOverride == null) {
|
||||
return PASSTHROUGH;
|
||||
}
|
||||
else if (methodOverride instanceof LookupOverride) {
|
||||
return LOOKUP_OVERRIDE;
|
||||
}
|
||||
else if (methodOverride instanceof ReplaceOverride) {
|
||||
return METHOD_REPLACER;
|
||||
}
|
||||
throw new UnsupportedOperationException(
|
||||
"Unexpected MethodOverride subclass: " + methodOverride.getClass().getName());
|
||||
@Override
|
||||
public int accept(Method method) {
|
||||
MethodOverride methodOverride = getBeanDefinition().getMethodOverrides().getOverride(method);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Override for '" + method.getName() + "' is [" + methodOverride + "]");
|
||||
}
|
||||
if (methodOverride == null) {
|
||||
return PASSTHROUGH;
|
||||
}
|
||||
else if (methodOverride instanceof LookupOverride) {
|
||||
return LOOKUP_OVERRIDE;
|
||||
}
|
||||
else if (methodOverride instanceof ReplaceOverride) {
|
||||
return METHOD_REPLACER;
|
||||
}
|
||||
throw new UnsupportedOperationException("Unexpected MethodOverride subclass: "
|
||||
+ methodOverride.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CGLIB MethodInterceptor to override methods, replacing them with an
|
||||
* implementation that returns a bean looked up in the container.
|
||||
*/
|
||||
private static class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
|
||||
|
||||
private final BeanFactory owner;
|
||||
|
||||
|
||||
LookupOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
|
||||
super(beanDefinition);
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
|
||||
// Cast is safe, as CallbackFilter filters are used selectively.
|
||||
LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
|
||||
return this.owner.getBean(lo.getBeanName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CGLIB MethodInterceptor to override methods, replacing them with a call
|
||||
* to a generic MethodReplacer.
|
||||
*/
|
||||
private static class ReplaceOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
|
||||
|
||||
private final BeanFactory owner;
|
||||
|
||||
|
||||
ReplaceOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
|
||||
super(beanDefinition);
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
|
||||
ReplaceOverride ro = (ReplaceOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
|
||||
// TODO could cache if a singleton for minor performance optimization
|
||||
MethodReplacer mr = owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class);
|
||||
return mr.reimplement(obj, method, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+37
-38
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -54,12 +54,9 @@ import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Helper class for resolving constructors and factory methods.
|
||||
* Delegate for resolving constructors and factory methods.
|
||||
* Performs constructor resolution through argument matching.
|
||||
*
|
||||
* <p>Operates on an {@link AbstractBeanFactory} and an {@link InstantiationStrategy}.
|
||||
* Used by {@link AbstractAutowireCapableBeanFactory}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Mark Fisher
|
||||
@@ -71,11 +68,6 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
class ConstructorResolver {
|
||||
|
||||
private static final String CONSTRUCTOR_PROPERTIES_CLASS_NAME = "java.beans.ConstructorProperties";
|
||||
|
||||
private static final boolean constructorPropertiesAnnotationAvailable =
|
||||
ClassUtils.isPresent(CONSTRUCTOR_PROPERTIES_CLASS_NAME, ConstructorResolver.class.getClassLoader());
|
||||
|
||||
private final AbstractAutowireCapableBeanFactory beanFactory;
|
||||
|
||||
|
||||
@@ -183,10 +175,7 @@ class ConstructorResolver {
|
||||
ArgumentsHolder argsHolder;
|
||||
if (resolvedValues != null) {
|
||||
try {
|
||||
String[] paramNames = null;
|
||||
if (constructorPropertiesAnnotationAvailable) {
|
||||
paramNames = ConstructorPropertiesChecker.evaluateAnnotation(candidate, paramTypes.length);
|
||||
}
|
||||
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
|
||||
if (paramNames == null) {
|
||||
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
|
||||
if (pnd != null) {
|
||||
@@ -297,17 +286,21 @@ class ConstructorResolver {
|
||||
*/
|
||||
public void resolveFactoryMethodIfPossible(RootBeanDefinition mbd) {
|
||||
Class<?> factoryClass;
|
||||
boolean isStatic;
|
||||
if (mbd.getFactoryBeanName() != null) {
|
||||
factoryClass = this.beanFactory.getType(mbd.getFactoryBeanName());
|
||||
isStatic = false;
|
||||
}
|
||||
else {
|
||||
factoryClass = mbd.getBeanClass();
|
||||
isStatic = true;
|
||||
}
|
||||
factoryClass = ClassUtils.getUserClass(factoryClass);
|
||||
Method[] candidates = ReflectionUtils.getAllDeclaredMethods(factoryClass);
|
||||
|
||||
Method[] candidates = getCandidateMethods(factoryClass, mbd);
|
||||
Method uniqueCandidate = null;
|
||||
for (Method candidate : candidates) {
|
||||
if (mbd.isFactoryMethod(candidate)) {
|
||||
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
|
||||
if (uniqueCandidate == null) {
|
||||
uniqueCandidate = candidate;
|
||||
}
|
||||
@@ -322,6 +315,27 @@ class ConstructorResolver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all candidate methods for the given class, considering
|
||||
* the {@link RootBeanDefinition#isNonPublicAccessAllowed()} flag.
|
||||
* Called as the starting point for factory method determination.
|
||||
*/
|
||||
private Method[] getCandidateMethods(final Class<?> factoryClass, final RootBeanDefinition mbd) {
|
||||
if (System.getSecurityManager() != null) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
|
||||
@Override
|
||||
public Method[] run() {
|
||||
return (mbd.isNonPublicAccessAllowed() ?
|
||||
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
return (mbd.isNonPublicAccessAllowed() ?
|
||||
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate the bean using a named factory method. The method may be static, if the
|
||||
* bean definition parameter specifies a class, rather than a "factory-bean", or
|
||||
@@ -337,7 +351,9 @@ class ConstructorResolver {
|
||||
* method, or {@code null} if none (-> use constructor argument values from bean definition)
|
||||
* @return a BeanWrapper for the new instance
|
||||
*/
|
||||
public BeanWrapper instantiateUsingFactoryMethod(final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) {
|
||||
public BeanWrapper instantiateUsingFactoryMethod(
|
||||
final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) {
|
||||
|
||||
BeanWrapperImpl bw = new BeanWrapperImpl();
|
||||
this.beanFactory.initBeanWrapper(bw);
|
||||
|
||||
@@ -398,28 +414,11 @@ class ConstructorResolver {
|
||||
// Need to determine the factory method...
|
||||
// Try all methods with this name to see if they match the given arguments.
|
||||
factoryClass = ClassUtils.getUserClass(factoryClass);
|
||||
Method[] rawCandidates;
|
||||
|
||||
final Class<?> factoryClazz = factoryClass;
|
||||
if (System.getSecurityManager() != null) {
|
||||
rawCandidates = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
|
||||
@Override
|
||||
public Method[] run() {
|
||||
return (mbd.isNonPublicAccessAllowed() ?
|
||||
ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
rawCandidates = (mbd.isNonPublicAccessAllowed() ?
|
||||
ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
|
||||
}
|
||||
|
||||
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
|
||||
List<Method> candidateSet = new ArrayList<Method>();
|
||||
for (Method candidate : rawCandidates) {
|
||||
if (Modifier.isStatic(candidate.getModifiers()) == isStatic &&
|
||||
candidate.getName().equals(mbd.getFactoryMethodName()) &&
|
||||
mbd.isFactoryMethod(candidate)) {
|
||||
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
|
||||
candidateSet.add(candidate);
|
||||
}
|
||||
}
|
||||
@@ -880,11 +879,11 @@ class ConstructorResolver {
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to avoid a Java 6 dependency.
|
||||
* Delegate for checking Java 6's {@link ConstructorProperties} annotation.
|
||||
*/
|
||||
private static class ConstructorPropertiesChecker {
|
||||
|
||||
public static String[] evaluateAnnotation(Constructor<?> candidate, int paramCount) {
|
||||
public static String[] evaluate(Constructor<?> candidate, int paramCount) {
|
||||
ConstructorProperties cp = candidate.getAnnotation(ConstructorProperties.class);
|
||||
if (cp != null) {
|
||||
String[] names = cp.value();
|
||||
|
||||
+2
-4
@@ -106,12 +106,10 @@ public class GenericTypeAwareAutowireCandidateResolver implements AutowireCandid
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targetType == null) {
|
||||
if (targetType == null || (descriptor.fallbackMatchAllowed() && targetType.hasUnresolvableGenerics())) {
|
||||
return true;
|
||||
}
|
||||
if (descriptor.fallbackMatchAllowed() && targetType.hasUnresolvableGenerics()) {
|
||||
return descriptor.getDependencyType().isAssignableFrom(targetType.getRawClass());
|
||||
}
|
||||
// Full check for complex generic type match...
|
||||
return dependencyType.isAssignableFrom(targetType);
|
||||
}
|
||||
|
||||
|
||||
+4
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,8 +39,8 @@ public class LookupOverride extends MethodOverride {
|
||||
* Construct a new LookupOverride.
|
||||
* @param methodName the name of the method to override.
|
||||
* This method must have no arguments.
|
||||
* @param beanName name of the bean in the current BeanFactory
|
||||
* that the overriden method should return
|
||||
* @param beanName the name of the bean in the current BeanFactory
|
||||
* that the overridden method should return
|
||||
*/
|
||||
public LookupOverride(String methodName, String beanName) {
|
||||
super(methodName);
|
||||
@@ -55,16 +55,14 @@ public class LookupOverride extends MethodOverride {
|
||||
return this.beanName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Match method of the given name, with no parameters.
|
||||
* Match the method of the given name, with no parameters.
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(Method method) {
|
||||
return (method.getName().equals(getMethodName()) && method.getParameterTypes().length == 0);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LookupOverride for method '" + getMethodName() + "'; will return bean '" + this.beanName + "'";
|
||||
|
||||
+15
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,14 +23,15 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Object representing the override of a method on a managed
|
||||
* object by the IoC container.
|
||||
* Object representing the override of a method on a managed object by the IoC
|
||||
* container.
|
||||
*
|
||||
* <p>Note that the override mechanism is <i>not</i> intended as a
|
||||
* generic means of inserting crosscutting code: use AOP for that.
|
||||
* <p>Note that the override mechanism is <em>not</em> intended as a generic
|
||||
* means of inserting crosscutting code: use AOP for that.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 1.1
|
||||
*/
|
||||
public abstract class MethodOverride implements BeanMetadataElement {
|
||||
@@ -59,17 +60,18 @@ public abstract class MethodOverride implements BeanMetadataElement {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the overridden method has to be considered as overloaded
|
||||
* (that is, whether arg type matching has to happen).
|
||||
* <p>Default is "true"; can be switched to "false" to optimize runtime performance.
|
||||
* Set whether the overridden method is <em>overloaded</em> (i.e., whether argument
|
||||
* type matching needs to occur to disambiguate methods of the same name).
|
||||
* <p>Default is {@code true}; can be switched to {@code false} to optimize
|
||||
* runtime performance.
|
||||
*/
|
||||
protected void setOverloaded(boolean overloaded) {
|
||||
this.overloaded = overloaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the overridden method has to be considered as overloaded
|
||||
* (that is, whether arg type matching has to happen).
|
||||
* Return whether the overridden method is <em>overloaded</em> (i.e., whether argument
|
||||
* type matching needs to occur to disambiguate methods of the same name).
|
||||
*/
|
||||
protected boolean isOverloaded() {
|
||||
return this.overloaded;
|
||||
@@ -88,17 +90,15 @@ public abstract class MethodOverride implements BeanMetadataElement {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subclasses must override this to indicate whether they match
|
||||
* the given method. This allows for argument list checking
|
||||
* as well as method name checking.
|
||||
* Subclasses must override this to indicate whether they <em>match</em> the
|
||||
* given method. This allows for argument list checking as well as method
|
||||
* name checking.
|
||||
* @param method the method to check
|
||||
* @return whether this override matches the given method
|
||||
*/
|
||||
public abstract boolean matches(Method method);
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
@@ -109,7 +109,6 @@ public abstract class MethodOverride implements BeanMetadataElement {
|
||||
}
|
||||
MethodOverride that = (MethodOverride) other;
|
||||
return (ObjectUtils.nullSafeEquals(this.methodName, that.methodName) &&
|
||||
this.overloaded == that.overloaded &&
|
||||
ObjectUtils.nullSafeEquals(this.source, that.source));
|
||||
}
|
||||
|
||||
@@ -117,7 +116,6 @@ public abstract class MethodOverride implements BeanMetadataElement {
|
||||
public int hashCode() {
|
||||
int hashCode = ObjectUtils.nullSafeHashCode(this.methodName);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.source);
|
||||
hashCode = 29 * hashCode + (this.overloaded ? 1 : 0);
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
|
||||
+53
-28
@@ -18,9 +18,8 @@ package org.springframework.beans.factory.support;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -49,19 +48,10 @@ import org.springframework.util.Assert;
|
||||
@SuppressWarnings("serial")
|
||||
public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
|
||||
private final Set<Member> externallyManagedConfigMembers =
|
||||
Collections.newSetFromMap(new ConcurrentHashMap<Member, Boolean>(0));
|
||||
|
||||
private final Set<String> externallyManagedInitMethods =
|
||||
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(0));
|
||||
|
||||
private final Set<String> externallyManagedDestroyMethods =
|
||||
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(0));
|
||||
boolean allowCaching = true;
|
||||
|
||||
private BeanDefinitionHolder decoratedDefinition;
|
||||
|
||||
boolean allowCaching = true;
|
||||
|
||||
private volatile Class<?> targetType;
|
||||
|
||||
boolean isFactoryMethodUnique = false;
|
||||
@@ -91,6 +81,12 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
/** Package-visible field that indicates a before-instantiation post-processor having kicked in */
|
||||
volatile Boolean beforeInstantiationResolved;
|
||||
|
||||
private Set<Member> externallyManagedConfigMembers;
|
||||
|
||||
private Set<String> externallyManagedInitMethods;
|
||||
|
||||
private Set<String> externallyManagedDestroyMethods;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new RootBeanDefinition, to be configured through its bean
|
||||
@@ -175,8 +171,8 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
*/
|
||||
public RootBeanDefinition(RootBeanDefinition original) {
|
||||
super(original);
|
||||
this.decoratedDefinition = original.decoratedDefinition;
|
||||
this.allowCaching = original.allowCaching;
|
||||
this.decoratedDefinition = original.decoratedDefinition;
|
||||
this.targetType = original.targetType;
|
||||
this.isFactoryMethodUnique = original.isFactoryMethodUnique;
|
||||
}
|
||||
@@ -203,6 +199,20 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a target definition that is being decorated by this bean definition.
|
||||
*/
|
||||
public void setDecoratedDefinition(BeanDefinitionHolder decoratedDefinition) {
|
||||
this.decoratedDefinition = decoratedDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the target definition that is being decorated by this bean definition, if any.
|
||||
*/
|
||||
public BeanDefinitionHolder getDecoratedDefinition() {
|
||||
return this.decoratedDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the target type of this bean definition, if known in advance.
|
||||
*/
|
||||
@@ -245,37 +255,52 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void registerExternallyManagedConfigMember(Member configMember) {
|
||||
this.externallyManagedConfigMembers.add(configMember);
|
||||
synchronized (this.postProcessingLock) {
|
||||
if (this.externallyManagedConfigMembers == null) {
|
||||
this.externallyManagedConfigMembers = new HashSet<Member>(1);
|
||||
}
|
||||
this.externallyManagedConfigMembers.add(configMember);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isExternallyManagedConfigMember(Member configMember) {
|
||||
return this.externallyManagedConfigMembers.contains(configMember);
|
||||
synchronized (this.postProcessingLock) {
|
||||
return (this.externallyManagedConfigMembers != null &&
|
||||
this.externallyManagedConfigMembers.contains(configMember));
|
||||
}
|
||||
}
|
||||
|
||||
public void registerExternallyManagedInitMethod(String initMethod) {
|
||||
this.externallyManagedInitMethods.add(initMethod);
|
||||
synchronized (this.postProcessingLock) {
|
||||
if (this.externallyManagedInitMethods == null) {
|
||||
this.externallyManagedInitMethods = new HashSet<String>(1);
|
||||
}
|
||||
this.externallyManagedInitMethods.add(initMethod);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isExternallyManagedInitMethod(String initMethod) {
|
||||
return this.externallyManagedInitMethods.contains(initMethod);
|
||||
synchronized (this.postProcessingLock) {
|
||||
return (this.externallyManagedInitMethods != null &&
|
||||
this.externallyManagedInitMethods.contains(initMethod));
|
||||
}
|
||||
}
|
||||
|
||||
public void registerExternallyManagedDestroyMethod(String destroyMethod) {
|
||||
this.externallyManagedDestroyMethods.add(destroyMethod);
|
||||
synchronized (this.postProcessingLock) {
|
||||
if (this.externallyManagedDestroyMethods == null) {
|
||||
this.externallyManagedDestroyMethods = new HashSet<String>(1);
|
||||
}
|
||||
this.externallyManagedDestroyMethods.add(destroyMethod);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isExternallyManagedDestroyMethod(String destroyMethod) {
|
||||
return this.externallyManagedDestroyMethods.contains(destroyMethod);
|
||||
}
|
||||
|
||||
public void setDecoratedDefinition(BeanDefinitionHolder decoratedDefinition) {
|
||||
this.decoratedDefinition = decoratedDefinition;
|
||||
}
|
||||
|
||||
public BeanDefinitionHolder getDecoratedDefinition() {
|
||||
return this.decoratedDefinition;
|
||||
synchronized (this.postProcessingLock) {
|
||||
return (this.externallyManagedDestroyMethods != null &&
|
||||
this.externallyManagedDestroyMethods.contains(destroyMethod));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Spring XML Beans Schema, version 3.2
|
||||
Spring XML Beans Schema, version 4.0
|
||||
Authors: Juergen Hoeller, Rob Harrop, Mark Fisher, Chris Beams
|
||||
|
||||
This defines a simple and consistent way of creating a namespace
|
||||
|
||||
@@ -189,9 +189,13 @@ public final class BeanUtilsTests {
|
||||
public void testCopyPropertiesWithInvalidProperty() {
|
||||
InvalidProperty source = new InvalidProperty();
|
||||
source.setName("name");
|
||||
source.setFlag1(true);
|
||||
source.setFlag2(true);
|
||||
InvalidProperty target = new InvalidProperty();
|
||||
BeanUtils.copyProperties(source, target);
|
||||
assertEquals(target.getName(), "name");
|
||||
assertTrue(target.getFlag1());
|
||||
assertTrue(target.getFlag2());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -308,6 +312,10 @@ public final class BeanUtilsTests {
|
||||
|
||||
private String value;
|
||||
|
||||
private boolean flag1;
|
||||
|
||||
private boolean flag2;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
@@ -323,6 +331,22 @@ public final class BeanUtilsTests {
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public void setFlag1(boolean flag1) {
|
||||
this.flag1 = flag1;
|
||||
}
|
||||
|
||||
public Boolean getFlag1() {
|
||||
return this.flag1;
|
||||
}
|
||||
|
||||
public void setFlag2(Boolean flag2) {
|
||||
this.flag2 = flag2;
|
||||
}
|
||||
|
||||
public boolean getFlag2() {
|
||||
return this.flag2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,13 +16,6 @@
|
||||
|
||||
package org.springframework.beans;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
@@ -44,11 +37,16 @@ import java.util.TreeSet;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.beans.propertyeditors.CustomNumberEditor;
|
||||
import org.springframework.beans.propertyeditors.StringArrayPropertyEditor;
|
||||
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
|
||||
import org.springframework.beans.support.DerivedFromProtectedBaseBean;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.tests.Assume;
|
||||
import org.springframework.tests.TestGroup;
|
||||
import org.springframework.tests.sample.beans.BooleanTestBean;
|
||||
@@ -56,15 +54,10 @@ import org.springframework.tests.sample.beans.ITestBean;
|
||||
import org.springframework.tests.sample.beans.IndexedTestBean;
|
||||
import org.springframework.tests.sample.beans.NumberTestBean;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.util.StopWatch;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
@@ -1556,28 +1549,55 @@ public final class BeanWrapperTests {
|
||||
@Test
|
||||
public void cornerSpr10115() {
|
||||
Spr10115Bean foo = new Spr10115Bean();
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl();
|
||||
bwi.setWrappedInstance(foo);
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
|
||||
bwi.setPropertyValue("prop1", "val1");
|
||||
assertEquals("val1", Spr10115Bean.prop1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArrayToObject() throws Exception {
|
||||
public void testArrayToObject() {
|
||||
ArrayToObject foo = new ArrayToObject();
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl();
|
||||
bwi.setWrappedInstance(foo);
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
|
||||
|
||||
Object[] array = new Object[] {"1","2"};
|
||||
bwi.setPropertyValue("object", array );
|
||||
bwi.setPropertyValue("object", array);
|
||||
assertThat(foo.getObject(), equalTo((Object) array));
|
||||
|
||||
array = new Object[] {"1"};
|
||||
bwi.setPropertyValue("object", array );
|
||||
bwi.setPropertyValue("object", array);
|
||||
assertThat(foo.getObject(), equalTo((Object) array));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyTypeMismatch() {
|
||||
PropertyTypeMismatch foo = new PropertyTypeMismatch();
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
|
||||
bwi.setPropertyValue("object", "a String");
|
||||
assertEquals("a String", foo.value);
|
||||
assertEquals(8, bwi.getPropertyValue("object"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenericArraySetter() {
|
||||
SkipReaderStub foo = new SkipReaderStub();
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
|
||||
List<String> values = new LinkedList<String>();
|
||||
values.add("1");
|
||||
values.add("2");
|
||||
values.add("3");
|
||||
values.add("4");
|
||||
bwi.setPropertyValue("items", values);
|
||||
Object[] result = foo.items;
|
||||
assertEquals(4, result.length);
|
||||
assertEquals("1", result[0]);
|
||||
assertEquals("2", result[1]);
|
||||
assertEquals("3", result[2]);
|
||||
assertEquals("4", result[3]);
|
||||
}
|
||||
|
||||
|
||||
static class Spr10115Bean {
|
||||
|
||||
private static String prop1;
|
||||
|
||||
public static void setProp1(String prop1) {
|
||||
@@ -1962,11 +1982,10 @@ public final class BeanWrapperTests {
|
||||
}
|
||||
|
||||
|
||||
static class ArrayToObject {
|
||||
public static class ArrayToObject {
|
||||
|
||||
private Object object;
|
||||
|
||||
|
||||
public void setObject(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
@@ -1974,6 +1993,37 @@ public final class BeanWrapperTests {
|
||||
public Object getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class PropertyTypeMismatch {
|
||||
|
||||
public String value;
|
||||
|
||||
public void setObject(String object) {
|
||||
this.value = object;
|
||||
}
|
||||
|
||||
public Integer getObject() {
|
||||
return (this.value != null ? this.value.length() : null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class SkipReaderStub<T> {
|
||||
|
||||
public T[] items;
|
||||
|
||||
public SkipReaderStub() {
|
||||
}
|
||||
|
||||
public SkipReaderStub(T... items) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public void setItems(T... items) {
|
||||
this.items = items;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+40
@@ -769,6 +769,21 @@ public class BeanFactoryGenericsTests {
|
||||
assertEquals(1, beans.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpr11250() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
|
||||
|
||||
bf.registerBeanDefinition("doubleStore", new RootBeanDefinition(NumberStore.class));
|
||||
bf.registerBeanDefinition("floatStore", new RootBeanDefinition(NumberStore.class));
|
||||
bf.registerBeanDefinition("numberBean",
|
||||
new RootBeanDefinition(NumberBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
|
||||
|
||||
NumberBean nb = bf.getBean(NumberBean.class);
|
||||
assertNotNull(nb.getDoubleStore());
|
||||
assertNotNull(nb.getFloatStore());
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class NamedUrlList extends LinkedList<URL> {
|
||||
@@ -831,4 +846,29 @@ public class BeanFactoryGenericsTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class NumberStore<T extends Number> {
|
||||
}
|
||||
|
||||
|
||||
public static class NumberBean {
|
||||
|
||||
private final NumberStore<Double> doubleStore;
|
||||
|
||||
private final NumberStore<Float> floatStore;
|
||||
|
||||
public NumberBean(NumberStore<Double> doubleStore, NumberStore<Float> floatStore) {
|
||||
this.doubleStore = doubleStore;
|
||||
this.floatStore = floatStore;
|
||||
}
|
||||
|
||||
public NumberStore<Double> getDoubleStore() {
|
||||
return this.doubleStore;
|
||||
}
|
||||
|
||||
public NumberStore<Float> getFloatStore() {
|
||||
return this.floatStore;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+61
-23
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,62 +16,95 @@
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
||||
/**
|
||||
* @author Rob Harrop
|
||||
*/
|
||||
public class DefinitionMetadataEqualsHashCodeTests extends TestCase {
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public void testRootBeanDefinitionEqualsAndHashCode() throws Exception {
|
||||
/**
|
||||
* Unit tests for {@code equals()} and {@code hashCode()} in bean definitions.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class DefinitionMetadataEqualsHashCodeTests {
|
||||
|
||||
@Test
|
||||
public void rootBeanDefinition() {
|
||||
RootBeanDefinition master = new RootBeanDefinition(TestBean.class);
|
||||
RootBeanDefinition equal = new RootBeanDefinition(TestBean.class);
|
||||
RootBeanDefinition notEqual = new RootBeanDefinition(String.class);
|
||||
RootBeanDefinition subclass = new RootBeanDefinition(TestBean.class) {};
|
||||
RootBeanDefinition subclass = new RootBeanDefinition(TestBean.class) {
|
||||
};
|
||||
setBaseProperties(master);
|
||||
setBaseProperties(equal);
|
||||
setBaseProperties(notEqual);
|
||||
setBaseProperties(subclass);
|
||||
|
||||
assertEqualsContract(master, equal, notEqual, subclass);
|
||||
assertEquals("Hash code for equal instances should match", master.hashCode(), equal.hashCode());
|
||||
assertEqualsAndHashCodeContracts(master, equal, notEqual, subclass);
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public void testChildBeanDefinitionEqualsAndHashCode() throws Exception {
|
||||
/**
|
||||
* @since 3.2.8
|
||||
* @see <a href="https://jira.springsource.org/browse/SPR-11420">SPR-11420</a>
|
||||
*/
|
||||
@Test
|
||||
public void rootBeanDefinitionAndMethodOverridesWithDifferentOverloadedValues() {
|
||||
RootBeanDefinition master = new RootBeanDefinition(TestBean.class);
|
||||
RootBeanDefinition equal = new RootBeanDefinition(TestBean.class);
|
||||
|
||||
setBaseProperties(master);
|
||||
setBaseProperties(equal);
|
||||
|
||||
// Simulate AbstractBeanDefinition.validate() which delegates to
|
||||
// AbstractBeanDefinition.prepareMethodOverrides():
|
||||
master.getMethodOverrides().getOverrides().iterator().next().setOverloaded(false);
|
||||
// But do not simulate validation of the 'equal' bean. As a consequence, a method
|
||||
// override in 'equal' will be marked as overloaded, but the corresponding
|
||||
// override in 'master' will not. But... the bean definitions should still be
|
||||
// considered equal.
|
||||
|
||||
assertEquals("Should be equal", master, equal);
|
||||
assertEquals("Hash code for equal instances must match", master.hashCode(), equal.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void childBeanDefinition() {
|
||||
ChildBeanDefinition master = new ChildBeanDefinition("foo");
|
||||
ChildBeanDefinition equal = new ChildBeanDefinition("foo");
|
||||
ChildBeanDefinition notEqual = new ChildBeanDefinition("bar");
|
||||
ChildBeanDefinition subclass = new ChildBeanDefinition("foo"){};
|
||||
ChildBeanDefinition subclass = new ChildBeanDefinition("foo") {
|
||||
};
|
||||
setBaseProperties(master);
|
||||
setBaseProperties(equal);
|
||||
setBaseProperties(notEqual);
|
||||
setBaseProperties(subclass);
|
||||
|
||||
assertEqualsContract(master, equal, notEqual, subclass);
|
||||
assertEquals("Hash code for equal instances should match", master.hashCode(), equal.hashCode());
|
||||
assertEqualsAndHashCodeContracts(master, equal, notEqual, subclass);
|
||||
}
|
||||
|
||||
public void testRuntimeBeanReference() throws Exception {
|
||||
@Test
|
||||
public void runtimeBeanReference() {
|
||||
RuntimeBeanReference master = new RuntimeBeanReference("name");
|
||||
RuntimeBeanReference equal = new RuntimeBeanReference("name");
|
||||
RuntimeBeanReference notEqual = new RuntimeBeanReference("someOtherName");
|
||||
RuntimeBeanReference subclass = new RuntimeBeanReference("name"){};
|
||||
assertEqualsContract(master, equal, notEqual, subclass);
|
||||
RuntimeBeanReference subclass = new RuntimeBeanReference("name") {
|
||||
};
|
||||
assertEqualsAndHashCodeContracts(master, equal, notEqual, subclass);
|
||||
}
|
||||
|
||||
private void setBaseProperties(AbstractBeanDefinition definition) {
|
||||
definition.setAbstract(true);
|
||||
definition.setAttribute("foo", "bar");
|
||||
definition.setAutowireCandidate(false);
|
||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
|
||||
//definition.getConstructorArgumentValues().addGenericArgumentValue("foo");
|
||||
// definition.getConstructorArgumentValues().addGenericArgumentValue("foo");
|
||||
definition.setDependencyCheck(AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS);
|
||||
definition.setDependsOn(new String[]{"foo", "bar"});
|
||||
definition.setDependsOn(new String[] { "foo", "bar" });
|
||||
definition.setDestroyMethodName("destroy");
|
||||
definition.setEnforceDestroyMethod(false);
|
||||
definition.setEnforceInitMethod(true);
|
||||
@@ -88,10 +121,15 @@ public class DefinitionMetadataEqualsHashCodeTests extends TestCase {
|
||||
definition.setSource("foo");
|
||||
}
|
||||
|
||||
private void assertEqualsContract(Object master, Object equal, Object notEqual, Object subclass) {
|
||||
private void assertEqualsAndHashCodeContracts(Object master, Object equal, Object notEqual, Object subclass) {
|
||||
assertEquals("Should be equal", master, equal);
|
||||
assertFalse("Should not be equal", master.equals(notEqual));
|
||||
assertEquals("Hash code for equal instances should match", master.hashCode(), equal.hashCode());
|
||||
|
||||
assertNotEquals("Should not be equal", master, notEqual);
|
||||
assertNotEquals("Hash code for non-equal instances should not match", master.hashCode(), notEqual.hashCode());
|
||||
|
||||
assertEquals("Subclass should be equal", master, subclass);
|
||||
assertEquals("Hash code for subclass should match", master.hashCode(), subclass.hashCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -50,12 +50,12 @@ public class EhCacheCache implements Cache {
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
public final String getName() {
|
||||
return this.cache.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ehcache getNativeCache() {
|
||||
public final Ehcache getNativeCache() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+11
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,7 +46,7 @@ public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManag
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new EhCacheCacheManager for the given backing EhCache.
|
||||
* Create a new EhCacheCacheManager for the given backing EhCache CacheManager.
|
||||
* @param cacheManager the backing EhCache {@link net.sf.ehcache.CacheManager}
|
||||
*/
|
||||
public EhCacheCacheManager(net.sf.ehcache.CacheManager cacheManager) {
|
||||
@@ -71,15 +71,16 @@ public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManag
|
||||
|
||||
@Override
|
||||
protected Collection<Cache> loadCaches() {
|
||||
Assert.notNull(this.cacheManager, "A backing EhCache CacheManager is required");
|
||||
Status status = this.cacheManager.getStatus();
|
||||
net.sf.ehcache.CacheManager cacheManager = getCacheManager();
|
||||
Assert.notNull(cacheManager, "A backing EhCache CacheManager is required");
|
||||
Status status = cacheManager.getStatus();
|
||||
Assert.isTrue(Status.STATUS_ALIVE.equals(status),
|
||||
"An 'alive' EhCache CacheManager is required - current cache is " + status.toString());
|
||||
|
||||
String[] names = this.cacheManager.getCacheNames();
|
||||
String[] names = cacheManager.getCacheNames();
|
||||
Collection<Cache> caches = new LinkedHashSet<Cache>(names.length);
|
||||
for (String name : names) {
|
||||
caches.add(new EhCacheCache(this.cacheManager.getEhcache(name)));
|
||||
caches.add(new EhCacheCache(cacheManager.getEhcache(name)));
|
||||
}
|
||||
return caches;
|
||||
}
|
||||
@@ -88,12 +89,11 @@ public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManag
|
||||
public Cache getCache(String name) {
|
||||
Cache cache = super.getCache(name);
|
||||
if (cache == null) {
|
||||
// check the EhCache cache again
|
||||
// (in case the cache was added at runtime)
|
||||
Ehcache ehcache = this.cacheManager.getEhcache(name);
|
||||
// Check the EhCache cache again (in case the cache was added at runtime)
|
||||
Ehcache ehcache = getCacheManager().getEhcache(name);
|
||||
if (ehcache != null) {
|
||||
cache = new EhCacheCache(ehcache);
|
||||
addCache(cache);
|
||||
addCache(new EhCacheCache(ehcache));
|
||||
cache = super.getCache(name); // potentially decorated
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
|
||||
Vendored
+20
-7
@@ -37,6 +37,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link FactoryBean} that creates a named EhCache {@link net.sf.ehcache.Cache} instance
|
||||
@@ -63,6 +64,11 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
*/
|
||||
public class EhCacheFactoryBean extends CacheConfiguration implements FactoryBean<Ehcache>, BeanNameAware, InitializingBean {
|
||||
|
||||
// EhCache's setStatisticsEnabled(boolean) available? Not anymore as of EhCache 2.7...
|
||||
private static final boolean setStatisticsAvailable =
|
||||
ClassUtils.hasMethod(Ehcache.class, "setStatisticsEnabled", boolean.class);
|
||||
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private CacheManager cacheManager;
|
||||
@@ -188,7 +194,9 @@ public class EhCacheFactoryBean extends CacheConfiguration implements FactoryBea
|
||||
|
||||
/**
|
||||
* Set whether to enable EhCache statistics on this cache.
|
||||
* @see net.sf.ehcache.Cache#setStatisticsEnabled
|
||||
* <p>Note: As of EhCache 2.7, statistics are enabled by default, and cannot be turned off.
|
||||
* This setter therefore has no effect in such a scenario.
|
||||
* @see net.sf.ehcache.Ehcache#setStatisticsEnabled
|
||||
*/
|
||||
public void setStatisticsEnabled(boolean statisticsEnabled) {
|
||||
this.statisticsEnabled = statisticsEnabled;
|
||||
@@ -196,7 +204,9 @@ public class EhCacheFactoryBean extends CacheConfiguration implements FactoryBea
|
||||
|
||||
/**
|
||||
* Set whether to enable EhCache's sampled statistics on this cache.
|
||||
* @see net.sf.ehcache.Cache#setSampledStatisticsEnabled
|
||||
* <p>Note: As of EhCache 2.7, statistics are enabled by default, and cannot be turned off.
|
||||
* This setter therefore has no effect in such a scenario.
|
||||
* @see net.sf.ehcache.Ehcache#setSampledStatisticsEnabled
|
||||
*/
|
||||
public void setSampledStatisticsEnabled(boolean sampledStatisticsEnabled) {
|
||||
this.sampledStatisticsEnabled = sampledStatisticsEnabled;
|
||||
@@ -263,11 +273,14 @@ public class EhCacheFactoryBean extends CacheConfiguration implements FactoryBea
|
||||
this.cacheManager.addCache(rawCache);
|
||||
}
|
||||
|
||||
if (this.statisticsEnabled) {
|
||||
rawCache.setStatisticsEnabled(true);
|
||||
}
|
||||
if (this.sampledStatisticsEnabled) {
|
||||
rawCache.setSampledStatisticsEnabled(true);
|
||||
// Only necessary on EhCache <2.7: As of 2.7, statistics are on by default.
|
||||
if (setStatisticsAvailable) {
|
||||
if (this.statisticsEnabled) {
|
||||
rawCache.setStatisticsEnabled(true);
|
||||
}
|
||||
if (this.sampledStatisticsEnabled) {
|
||||
rawCache.setSampledStatisticsEnabled(true);
|
||||
}
|
||||
}
|
||||
if (this.disabled) {
|
||||
rawCache.setDisabled(true);
|
||||
|
||||
+3
-3
@@ -67,16 +67,16 @@ public class GuavaCache implements Cache {
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
public final String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.google.common.cache.Cache<Object, Object> getNativeCache() {
|
||||
public final com.google.common.cache.Cache<Object, Object> getNativeCache() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
public boolean isAllowNullValues() {
|
||||
public final boolean isAllowNullValues() {
|
||||
return this.allowNullValues;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+22
-11
@@ -26,7 +26,6 @@ import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheBuilderSpec;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -49,7 +48,7 @@ import org.springframework.util.Assert;
|
||||
* @since 4.0
|
||||
* @see GuavaCache
|
||||
*/
|
||||
public class GuavaCacheManager implements CacheManager, DisposableBean {
|
||||
public class GuavaCacheManager implements CacheManager {
|
||||
|
||||
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>(16);
|
||||
|
||||
@@ -59,6 +58,8 @@ public class GuavaCacheManager implements CacheManager, DisposableBean {
|
||||
|
||||
private CacheLoader<Object, Object> cacheLoader;
|
||||
|
||||
private boolean allowNullValues = true;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a dynamic GuavaCacheManager,
|
||||
@@ -133,6 +134,24 @@ public class GuavaCacheManager implements CacheManager, DisposableBean {
|
||||
this.cacheLoader = cacheLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether to accept and convert {@code null} values for all caches
|
||||
* in this cache manager.
|
||||
* <p>Default is "true", despite Guava itself not supporting {@code null} values.
|
||||
* An internal holder object will be used to store user-level {@code null}s.
|
||||
*/
|
||||
public void setAllowNullValues(boolean allowNullValues) {
|
||||
this.allowNullValues = allowNullValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this cache manager accepts and converts {@code null} values
|
||||
* for all of its caches.
|
||||
*/
|
||||
public boolean isAllowNullValues() {
|
||||
return this.allowNullValues;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<String> getCacheNames() {
|
||||
@@ -160,7 +179,7 @@ public class GuavaCacheManager implements CacheManager, DisposableBean {
|
||||
* @return the Spring GuavaCache adapter (or a decorator thereof)
|
||||
*/
|
||||
protected Cache createGuavaCache(String name) {
|
||||
return new GuavaCache(name, createNativeGuavaCache(name));
|
||||
return new GuavaCache(name, createNativeGuavaCache(name), isAllowNullValues());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,12 +196,4 @@ public class GuavaCacheManager implements CacheManager, DisposableBean {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
for (Cache cache : this.cacheMap.values()) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-11
@@ -26,7 +26,7 @@ import org.springframework.util.Assert;
|
||||
* {@link org.springframework.cache.Cache} implementation on top of a
|
||||
* {@link javax.cache.Cache} instance.
|
||||
*
|
||||
* <p>Note: This class has been updated for JCache 0.11, as of Spring 4.0.
|
||||
* <p>Note: This class has been updated for JCache 1.0, as of Spring 4.0.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.2
|
||||
@@ -35,8 +35,7 @@ public class JCacheCache implements Cache {
|
||||
|
||||
private static final Object NULL_HOLDER = new NullHolder();
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final javax.cache.Cache cache;
|
||||
private final javax.cache.Cache<Object, Object> cache;
|
||||
|
||||
private final boolean allowNullValues;
|
||||
|
||||
@@ -45,7 +44,7 @@ public class JCacheCache implements Cache {
|
||||
* Create an {@link org.springframework.cache.jcache.JCacheCache} instance.
|
||||
* @param jcache backing JCache Cache instance
|
||||
*/
|
||||
public JCacheCache(javax.cache.Cache<?,?> jcache) {
|
||||
public JCacheCache(javax.cache.Cache<Object, Object> jcache) {
|
||||
this(jcache, true);
|
||||
}
|
||||
|
||||
@@ -54,7 +53,7 @@ public class JCacheCache implements Cache {
|
||||
* @param jcache backing JCache Cache instance
|
||||
* @param allowNullValues whether to accept and convert null values for this cache
|
||||
*/
|
||||
public JCacheCache(javax.cache.Cache<?,?> jcache, boolean allowNullValues) {
|
||||
public JCacheCache(javax.cache.Cache<Object, Object> jcache, boolean allowNullValues) {
|
||||
Assert.notNull(jcache, "Cache must not be null");
|
||||
this.cache = jcache;
|
||||
this.allowNullValues = allowNullValues;
|
||||
@@ -62,21 +61,20 @@ public class JCacheCache implements Cache {
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
public final String getName() {
|
||||
return this.cache.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public javax.cache.Cache<?,?> getNativeCache() {
|
||||
public final javax.cache.Cache<Object, Object> getNativeCache() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
public boolean isAllowNullValues() {
|
||||
public final boolean isAllowNullValues() {
|
||||
return this.allowNullValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ValueWrapper get(Object key) {
|
||||
Object value = this.cache.get(key);
|
||||
return (value != null ? new SimpleValueWrapper(fromStoreValue(value)) : null);
|
||||
@@ -93,13 +91,11 @@ public class JCacheCache implements Cache {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void put(Object key, Object value) {
|
||||
this.cache.put(key, toStoreValue(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void evict(Object key) {
|
||||
this.cache.remove(key);
|
||||
}
|
||||
|
||||
Vendored
+15
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,7 +28,7 @@ import org.springframework.cache.transaction.AbstractTransactionSupportingCacheM
|
||||
* {@link org.springframework.cache.CacheManager} implementation
|
||||
* backed by a JCache {@link javax.cache.CacheManager}.
|
||||
*
|
||||
* <p>Note: This class has been updated for JCache 0.11, as of Spring 4.0.
|
||||
* <p>Note: This class has been updated for JCache 1.0, as of Spring 4.0.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.2
|
||||
@@ -71,17 +71,17 @@ public class JCacheCacheManager extends AbstractTransactionSupportingCacheManage
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether to accept and convert null values for all caches
|
||||
* Specify whether to accept and convert {@code null} values for all caches
|
||||
* in this cache manager.
|
||||
* <p>Default is "true", despite JSR-107 itself not supporting null values.
|
||||
* An internal holder object will be used to store user-level null values.
|
||||
* <p>Default is "true", despite JSR-107 itself not supporting {@code null} values.
|
||||
* An internal holder object will be used to store user-level {@code null}s.
|
||||
*/
|
||||
public void setAllowNullValues(boolean allowNullValues) {
|
||||
this.allowNullValues = allowNullValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this cache manager accepts and converts null values
|
||||
* Return whether this cache manager accepts and converts {@code null} values
|
||||
* for all of its caches.
|
||||
*/
|
||||
public boolean isAllowNullValues() {
|
||||
@@ -90,8 +90,8 @@ public class JCacheCacheManager extends AbstractTransactionSupportingCacheManage
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (this.cacheManager == null) {
|
||||
this.cacheManager = Caching.getCachingProvider().getCacheManager();
|
||||
if (getCacheManager() == null) {
|
||||
setCacheManager(Caching.getCachingProvider().getCacheManager());
|
||||
}
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
@@ -100,9 +100,9 @@ public class JCacheCacheManager extends AbstractTransactionSupportingCacheManage
|
||||
@Override
|
||||
protected Collection<Cache> loadCaches() {
|
||||
Collection<Cache> caches = new LinkedHashSet<Cache>();
|
||||
for (String cacheName : this.cacheManager.getCacheNames()) {
|
||||
javax.cache.Cache<Object, Object> jcache = this.cacheManager.getCache(cacheName);
|
||||
caches.add(new JCacheCache(jcache, this.allowNullValues));
|
||||
for (String cacheName : getCacheManager().getCacheNames()) {
|
||||
javax.cache.Cache<Object, Object> jcache = getCacheManager().getCache(cacheName);
|
||||
caches.add(new JCacheCache(jcache, isAllowNullValues()));
|
||||
}
|
||||
return caches;
|
||||
}
|
||||
@@ -111,12 +111,11 @@ public class JCacheCacheManager extends AbstractTransactionSupportingCacheManage
|
||||
public Cache getCache(String name) {
|
||||
Cache cache = super.getCache(name);
|
||||
if (cache == null) {
|
||||
// check the JCache cache again
|
||||
// (in case the cache was added at runtime)
|
||||
javax.cache.Cache<?,?> jcache = this.cacheManager.getCache(name);
|
||||
// Check the JCache cache again (in case the cache was added at runtime)
|
||||
javax.cache.Cache<Object, Object> jcache = getCacheManager().getCache(name);
|
||||
if (jcache != null) {
|
||||
cache = new JCacheCache(jcache, this.allowNullValues);
|
||||
addCache(cache);
|
||||
addCache(new JCacheCache(jcache, isAllowNullValues()));
|
||||
cache = super.getCache(name); // potentially decorated
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
|
||||
Vendored
+1
-1
@@ -32,7 +32,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
* obtaining a pre-defined CacheManager by name through the standard
|
||||
* JCache {@link javax.cache.Caching} class.
|
||||
*
|
||||
* <p>Note: This class has been updated for JCache 0.11, as of Spring 4.0.
|
||||
* <p>Note: This class has been updated for JCache 1.0, as of Spring 4.0.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.2
|
||||
|
||||
+18
-2
@@ -20,7 +20,6 @@ import java.util.Collection;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import commonj.work.Work;
|
||||
@@ -31,11 +30,14 @@ import commonj.work.WorkManager;
|
||||
import commonj.work.WorkRejectedException;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.core.task.TaskRejectedException;
|
||||
import org.springframework.jndi.JndiLocatorSupport;
|
||||
import org.springframework.scheduling.SchedulingException;
|
||||
import org.springframework.scheduling.SchedulingTaskExecutor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureTask;
|
||||
|
||||
/**
|
||||
* TaskExecutor implementation that delegates to a CommonJ WorkManager,
|
||||
@@ -61,7 +63,7 @@ import org.springframework.util.Assert;
|
||||
* @since 2.0
|
||||
*/
|
||||
public class WorkManagerTaskExecutor extends JndiLocatorSupport
|
||||
implements SchedulingTaskExecutor, WorkManager, InitializingBean {
|
||||
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor, WorkManager, InitializingBean {
|
||||
|
||||
private WorkManager workManager;
|
||||
|
||||
@@ -153,6 +155,20 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<?> submitListenable(Runnable task) {
|
||||
ListenableFutureTask<Object> future = new ListenableFutureTask<Object>(task, null);
|
||||
execute(future);
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
|
||||
ListenableFutureTask<T> future = new ListenableFutureTask<T>(task);
|
||||
execute(future);
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
* This task executor prefers short-lived work units.
|
||||
*/
|
||||
|
||||
+1
@@ -31,6 +31,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* objects as well as standard Quartz {@link org.quartz.Job} instances.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.8 as well as Quartz 2.0-2.2, as of Spring 4.0.
|
||||
* <b>Note:</b> Quartz 1.x support is deprecated - please upgrade to Quartz 2.0+.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
|
||||
+9
-11
@@ -73,7 +73,7 @@ public class CronTriggerBean extends CronTrigger
|
||||
|
||||
private String beanName;
|
||||
|
||||
private long startDelay;
|
||||
private long startDelay = 0;
|
||||
|
||||
|
||||
/**
|
||||
@@ -107,10 +107,12 @@ public class CronTriggerBean extends CronTrigger
|
||||
* by the TriggerListener implementation.
|
||||
* @see SchedulerFactoryBean#setTriggerListeners
|
||||
* @see org.quartz.TriggerListener#getName
|
||||
* @deprecated as of Spring 4.0, since it only works on Quartz 1.x
|
||||
*/
|
||||
public void setTriggerListenerNames(String[] names) {
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
addTriggerListener(names[i]);
|
||||
@Deprecated
|
||||
public void setTriggerListenerNames(String... names) {
|
||||
for (String name : names) {
|
||||
addTriggerListener(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,19 +153,15 @@ public class CronTriggerBean extends CronTrigger
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (this.startDelay > 0) {
|
||||
setStartTime(new Date(System.currentTimeMillis() + this.startDelay));
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
if (getName() == null) {
|
||||
setName(this.beanName);
|
||||
}
|
||||
if (getGroup() == null) {
|
||||
setGroup(Scheduler.DEFAULT_GROUP);
|
||||
}
|
||||
if (getStartTime() == null) {
|
||||
setStartTime(new Date());
|
||||
if (this.startDelay > 0 || getStartTime() == null) {
|
||||
setStartTime(new Date(System.currentTimeMillis() + this.startDelay));
|
||||
}
|
||||
if (getTimeZone() == null) {
|
||||
setTimeZone(TimeZone.getDefault());
|
||||
|
||||
+33
-5
@@ -78,16 +78,20 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
|
||||
private Date startTime;
|
||||
|
||||
private long startDelay;
|
||||
private long startDelay = 0;
|
||||
|
||||
private String cronExpression;
|
||||
|
||||
private TimeZone timeZone;
|
||||
|
||||
private String calendarName;
|
||||
|
||||
private int priority;
|
||||
|
||||
private int misfireInstruction;
|
||||
|
||||
private String description;
|
||||
|
||||
private String beanName;
|
||||
|
||||
private CronTrigger cronTrigger;
|
||||
@@ -141,6 +145,15 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
this.jobDataMap.putAll(jobDataAsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific start time for the trigger.
|
||||
* <p>Note that a dynamically computed {@link #setStartDelay} specification
|
||||
* overrides a static timestamp set here.
|
||||
*/
|
||||
public void setStartTime(Date startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the start delay in milliseconds.
|
||||
* <p>The start delay is added to the current system time (when the bean starts)
|
||||
@@ -165,6 +178,13 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
this.timeZone = timeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a specific calendar with this cron trigger.
|
||||
*/
|
||||
public void setCalendarName(String calendarName) {
|
||||
this.calendarName = calendarName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the priority of this trigger.
|
||||
*/
|
||||
@@ -191,6 +211,13 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
this.misfireInstruction = constants.asNumber(constantName).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a textual description with this trigger.
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
@@ -208,12 +235,9 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
if (this.jobDetail != null) {
|
||||
this.jobDataMap.put(JobDetailAwareTrigger.JOB_DETAIL_KEY, this.jobDetail);
|
||||
}
|
||||
if (this.startDelay > 0) {
|
||||
if (this.startDelay > 0 || this.startTime == null) {
|
||||
this.startTime = new Date(System.currentTimeMillis() + this.startDelay);
|
||||
}
|
||||
else if (this.startTime == null) {
|
||||
this.startTime = new Date();
|
||||
}
|
||||
if (this.timeZone == null) {
|
||||
this.timeZone = TimeZone.getDefault();
|
||||
}
|
||||
@@ -227,8 +251,10 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
cti.setStartTime(this.startTime);
|
||||
cti.setCronExpression(this.cronExpression);
|
||||
cti.setTimeZone(this.timeZone);
|
||||
cti.setCalendarName(this.calendarName);
|
||||
cti.setPriority(this.priority);
|
||||
cti.setMisfireInstruction(this.misfireInstruction);
|
||||
cti.setDescription(this.description);
|
||||
this.cronTrigger = cti;
|
||||
*/
|
||||
|
||||
@@ -260,8 +286,10 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
pvs.add("startTime", this.startTime);
|
||||
pvs.add("cronExpression", this.cronExpression);
|
||||
pvs.add("timeZone", this.timeZone);
|
||||
pvs.add("calendarName", this.calendarName);
|
||||
pvs.add("priority", this.priority);
|
||||
pvs.add("misfireInstruction", this.misfireInstruction);
|
||||
pvs.add("description", this.description);
|
||||
bw.setPropertyValues(pvs);
|
||||
this.cronTrigger = (CronTrigger) bw.getWrappedInstance();
|
||||
}
|
||||
|
||||
+8
-5
@@ -21,6 +21,7 @@ import java.util.Map;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobDetail;
|
||||
import org.quartz.Scheduler;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -47,7 +48,7 @@ import org.springframework.context.ApplicationContextAware;
|
||||
* @see org.springframework.beans.factory.BeanNameAware
|
||||
* @see org.quartz.Scheduler#DEFAULT_GROUP
|
||||
*/
|
||||
@SuppressWarnings({ "serial", "rawtypes" })
|
||||
@SuppressWarnings({"serial", "rawtypes"})
|
||||
public class JobDetailBean extends JobDetail
|
||||
implements BeanNameAware, ApplicationContextAware, InitializingBean {
|
||||
|
||||
@@ -96,7 +97,7 @@ public class JobDetailBean extends JobDetail
|
||||
* (for example Spring-managed beans)
|
||||
* @see SchedulerFactoryBean#setSchedulerContextAsMap
|
||||
*/
|
||||
public void setJobDataAsMap(Map jobDataAsMap) {
|
||||
public void setJobDataAsMap(Map<String, ?> jobDataAsMap) {
|
||||
getJobDataMap().putAll(jobDataAsMap);
|
||||
}
|
||||
|
||||
@@ -107,10 +108,12 @@ public class JobDetailBean extends JobDetail
|
||||
* by the JobListener implementation.
|
||||
* @see SchedulerFactoryBean#setJobListeners
|
||||
* @see org.quartz.JobListener#getName
|
||||
* @deprecated as of Spring 4.0, since it only works on Quartz 1.x
|
||||
*/
|
||||
public void setJobListenerNames(String[] names) {
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
addJobListener(names[i]);
|
||||
@Deprecated
|
||||
public void setJobListenerNames(String... names) {
|
||||
for (String name : names) {
|
||||
addJobListener(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -18,7 +18,6 @@ package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.quartz.SchedulerConfigException;
|
||||
@@ -110,14 +109,17 @@ public class LocalDataSourceJobStore extends JobStoreCMT {
|
||||
public void shutdown() {
|
||||
// Do nothing - a Spring-managed DataSource has its own lifecycle.
|
||||
}
|
||||
/* Quartz 2.2 initialize method */
|
||||
public void initialize() {
|
||||
// Do nothing - a Spring-managed DataSource has its own lifecycle.
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Non-transactional DataSource is optional: fall back to default
|
||||
// DataSource if not explicitly specified.
|
||||
DataSource nonTxDataSource = SchedulerFactoryBean.getConfigTimeNonTransactionalDataSource();
|
||||
final DataSource nonTxDataSourceToUse =
|
||||
(nonTxDataSource != null ? nonTxDataSource : this.dataSource);
|
||||
final DataSource nonTxDataSourceToUse = (nonTxDataSource != null ? nonTxDataSource : this.dataSource);
|
||||
|
||||
// Configure non-transactional connection settings for Quartz.
|
||||
setNonManagedTXDataSource(NON_TX_DATA_SOURCE_PREFIX + getInstanceName());
|
||||
@@ -135,21 +137,24 @@ public class LocalDataSourceJobStore extends JobStoreCMT {
|
||||
public void shutdown() {
|
||||
// Do nothing - a Spring-managed DataSource has its own lifecycle.
|
||||
}
|
||||
/* Quartz 2.2 initialize method */
|
||||
public void initialize() {
|
||||
// Do nothing - a Spring-managed DataSource has its own lifecycle.
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// No, if HSQL is the platform, we really don't want to use locks
|
||||
// No, if HSQL is the platform, we really don't want to use locks...
|
||||
try {
|
||||
String productName = JdbcUtils.extractDatabaseMetaData(dataSource,
|
||||
"getDatabaseProductName").toString();
|
||||
String productName = JdbcUtils.extractDatabaseMetaData(this.dataSource, "getDatabaseProductName").toString();
|
||||
productName = JdbcUtils.commonDatabaseName(productName);
|
||||
if (productName != null
|
||||
&& productName.toLowerCase().contains("hsql")) {
|
||||
if (productName != null && productName.toLowerCase().contains("hsql")) {
|
||||
setUseDBLocks(false);
|
||||
setLockHandler(new SimpleSemaphore());
|
||||
}
|
||||
} catch (MetaDataAccessException e) {
|
||||
logWarnIfNonZero(1, "Could not detect database type. Assuming locks can be taken.");
|
||||
}
|
||||
catch (MetaDataAccessException ex) {
|
||||
logWarnIfNonZero(1, "Could not detect database type. Assuming locks can be taken.");
|
||||
}
|
||||
|
||||
super.initialize(loadHelper, signaler);
|
||||
|
||||
+4
-1
@@ -68,6 +68,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* where you want a persistent job to delegate to a specific service method.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.8 as well as Quartz 2.0-2.2, as of Spring 4.0.
|
||||
* <b>Note:</b> Quartz 1.x support is deprecated - please upgrade to Quartz 2.0+.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Alef Arendsen
|
||||
@@ -171,8 +172,10 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
* by the JobListener implementation.
|
||||
* @see SchedulerFactoryBean#setJobListeners
|
||||
* @see org.quartz.JobListener#getName
|
||||
* @deprecated as of Spring 4.0, since it only works on Quartz 1.x
|
||||
*/
|
||||
public void setJobListenerNames(String[] names) {
|
||||
@Deprecated
|
||||
public void setJobListenerNames(String... names) {
|
||||
this.jobListenerNames = names;
|
||||
}
|
||||
|
||||
|
||||
+63
-21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -53,8 +53,10 @@ import org.springframework.util.ReflectionUtils;
|
||||
* {@link SchedulerAccessorBean} classes.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.8 as well as Quartz 2.0-2.2, as of Spring 4.0.
|
||||
* <b>Note:</b> Quartz 1.x support is deprecated - please upgrade to Quartz 2.0+.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.5.6
|
||||
*/
|
||||
public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
@@ -64,6 +66,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
private static Class<?> triggerKeyClass;
|
||||
|
||||
static {
|
||||
// Quartz 2.0 job/trigger key available?
|
||||
try {
|
||||
jobKeyClass = Class.forName("org.quartz.JobKey");
|
||||
triggerKeyClass = Class.forName("org.quartz.TriggerKey");
|
||||
@@ -102,6 +105,13 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
protected ResourceLoader resourceLoader;
|
||||
|
||||
|
||||
public SchedulerAccessor() {
|
||||
if (jobKeyClass == null && logger.isInfoEnabled()) {
|
||||
logger.info("Spring's Quartz 1.x support is deprecated - please upgrade to Quartz 2.0+");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether any jobs defined on this SchedulerFactoryBean should overwrite
|
||||
* existing job definitions. Default is "false", to not overwrite already
|
||||
@@ -129,7 +139,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* to jobs defined directly on this SchedulerFactoryBean.
|
||||
* @see org.quartz.xml.XMLSchedulingDataProcessor
|
||||
*/
|
||||
public void setJobSchedulingDataLocations(String[] jobSchedulingDataLocations) {
|
||||
public void setJobSchedulingDataLocations(String... jobSchedulingDataLocations) {
|
||||
this.jobSchedulingDataLocations = jobSchedulingDataLocations;
|
||||
}
|
||||
|
||||
@@ -143,9 +153,8 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* @see org.quartz.JobDetail
|
||||
* @see JobDetailBean
|
||||
* @see JobDetailAwareTrigger
|
||||
* @see org.quartz.Trigger#setJobName
|
||||
*/
|
||||
public void setJobDetails(JobDetail[] jobDetails) {
|
||||
public void setJobDetails(JobDetail... jobDetails) {
|
||||
// Use modifiable ArrayList here, to allow for further adding of
|
||||
// JobDetail objects during autodetection of JobDetailAwareTriggers.
|
||||
this.jobDetails = new ArrayList<JobDetail>(Arrays.asList(jobDetails));
|
||||
@@ -157,7 +166,6 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* @param calendars Map with calendar names as keys as Calendar
|
||||
* objects as values
|
||||
* @see org.quartz.Calendar
|
||||
* @see org.quartz.Trigger#setCalendarName
|
||||
*/
|
||||
public void setCalendars(Map<String, Calendar> calendars) {
|
||||
this.calendars = calendars;
|
||||
@@ -176,7 +184,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* @see CronTriggerBean
|
||||
* @see SimpleTriggerBean
|
||||
*/
|
||||
public void setTriggers(Trigger[] triggers) {
|
||||
public void setTriggers(Trigger... triggers) {
|
||||
this.triggers = Arrays.asList(triggers);
|
||||
}
|
||||
|
||||
@@ -184,7 +192,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
/**
|
||||
* Specify Quartz SchedulerListeners to be registered with the Scheduler.
|
||||
*/
|
||||
public void setSchedulerListeners(SchedulerListener[] schedulerListeners) {
|
||||
public void setSchedulerListeners(SchedulerListener... schedulerListeners) {
|
||||
this.schedulerListeners = schedulerListeners;
|
||||
}
|
||||
|
||||
@@ -192,7 +200,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* Specify global Quartz JobListeners to be registered with the Scheduler.
|
||||
* Such JobListeners will apply to all Jobs in the Scheduler.
|
||||
*/
|
||||
public void setGlobalJobListeners(JobListener[] globalJobListeners) {
|
||||
public void setGlobalJobListeners(JobListener... globalJobListeners) {
|
||||
this.globalJobListeners = globalJobListeners;
|
||||
}
|
||||
|
||||
@@ -200,11 +208,14 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* Specify named Quartz JobListeners to be registered with the Scheduler.
|
||||
* Such JobListeners will only apply to Jobs that explicitly activate
|
||||
* them via their name.
|
||||
* <p>Note that non-global JobListeners are not supported on Quartz 2.x -
|
||||
* manually register a Matcher against the Quartz ListenerManager instead.
|
||||
* @see org.quartz.JobListener#getName
|
||||
* @see org.quartz.JobDetail#addJobListener
|
||||
* @see JobDetailBean#setJobListenerNames
|
||||
* @deprecated as of Spring 4.0, since it only works on Quartz 1.x
|
||||
*/
|
||||
public void setJobListeners(JobListener[] jobListeners) {
|
||||
@Deprecated
|
||||
public void setJobListeners(JobListener... jobListeners) {
|
||||
this.jobListeners = jobListeners;
|
||||
}
|
||||
|
||||
@@ -212,7 +223,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* Specify global Quartz TriggerListeners to be registered with the Scheduler.
|
||||
* Such TriggerListeners will apply to all Triggers in the Scheduler.
|
||||
*/
|
||||
public void setGlobalTriggerListeners(TriggerListener[] globalTriggerListeners) {
|
||||
public void setGlobalTriggerListeners(TriggerListener... globalTriggerListeners) {
|
||||
this.globalTriggerListeners = globalTriggerListeners;
|
||||
}
|
||||
|
||||
@@ -220,12 +231,15 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* Specify named Quartz TriggerListeners to be registered with the Scheduler.
|
||||
* Such TriggerListeners will only apply to Triggers that explicitly activate
|
||||
* them via their name.
|
||||
* <p>Note that non-global TriggerListeners are not supported on Quartz 2.x -
|
||||
* manually register a Matcher against the Quartz ListenerManager instead.
|
||||
* @see org.quartz.TriggerListener#getName
|
||||
* @see org.quartz.Trigger#addTriggerListener
|
||||
* @see CronTriggerBean#setTriggerListenerNames
|
||||
* @see SimpleTriggerBean#setTriggerListenerNames
|
||||
* @deprecated as of Spring 4.0, since it only works on Quartz 1.x
|
||||
*/
|
||||
public void setTriggerListeners(TriggerListener[] triggerListeners) {
|
||||
@Deprecated
|
||||
public void setTriggerListeners(TriggerListener... triggerListeners) {
|
||||
this.triggerListeners = triggerListeners;
|
||||
}
|
||||
|
||||
@@ -382,7 +396,8 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
}
|
||||
else {
|
||||
try {
|
||||
Map<?, ?> jobDataMap = (Map<?, ?>) ReflectionUtils.invokeMethod(Trigger.class.getMethod("getJobDataMap"), trigger);
|
||||
Map<?, ?> jobDataMap =
|
||||
(Map<?, ?>) ReflectionUtils.invokeMethod(Trigger.class.getMethod("getJobDataMap"), trigger);
|
||||
return (JobDetail) jobDataMap.remove(JobDetailAwareTrigger.JOB_DETAIL_KEY);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
@@ -459,19 +474,33 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
target = getScheduler();
|
||||
quartz2 = false;
|
||||
}
|
||||
Class<?> targetClass = target.getClass();
|
||||
|
||||
try {
|
||||
if (this.schedulerListeners != null) {
|
||||
Method addSchedulerListener = target.getClass().getMethod("addSchedulerListener", SchedulerListener.class);
|
||||
Method addSchedulerListener = targetClass.getMethod("addSchedulerListener", SchedulerListener.class);
|
||||
for (SchedulerListener listener : this.schedulerListeners) {
|
||||
ReflectionUtils.invokeMethod(addSchedulerListener, target, listener);
|
||||
}
|
||||
}
|
||||
if (this.globalJobListeners != null) {
|
||||
Method addJobListener = target.getClass().getMethod(
|
||||
(quartz2 ? "addJobListener" : "addGlobalJobListener"), JobListener.class);
|
||||
Method addJobListener;
|
||||
if (quartz2) {
|
||||
// addJobListener(JobListener) only introduced as late as Quartz 2.2, so we need
|
||||
// to fall back to the Quartz 2.0/2.1 compatible variant with an empty matchers List
|
||||
addJobListener = targetClass.getMethod("addJobListener", JobListener.class, List.class);
|
||||
}
|
||||
else {
|
||||
addJobListener = targetClass.getMethod("addGlobalJobListener", JobListener.class);
|
||||
}
|
||||
for (JobListener listener : this.globalJobListeners) {
|
||||
ReflectionUtils.invokeMethod(addJobListener, target, listener);
|
||||
if (quartz2) {
|
||||
List<?> emptyMatchers = new LinkedList<Object>();
|
||||
ReflectionUtils.invokeMethod(addJobListener, target, listener, emptyMatchers);
|
||||
}
|
||||
else {
|
||||
ReflectionUtils.invokeMethod(addJobListener, target, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.jobListeners != null) {
|
||||
@@ -484,10 +513,23 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
}
|
||||
}
|
||||
if (this.globalTriggerListeners != null) {
|
||||
Method addTriggerListener = target.getClass().getMethod(
|
||||
(quartz2 ? "addTriggerListener" : "addGlobalTriggerListener"), TriggerListener.class);
|
||||
Method addTriggerListener;
|
||||
if (quartz2) {
|
||||
// addTriggerListener(TriggerListener) only introduced as late as Quartz 2.2, so we need
|
||||
// to fall back to the Quartz 2.0/2.1 compatible variant with an empty matchers List
|
||||
addTriggerListener = targetClass.getMethod("addTriggerListener", TriggerListener.class, List.class);
|
||||
}
|
||||
else {
|
||||
addTriggerListener = targetClass.getMethod("addGlobalTriggerListener", TriggerListener.class);
|
||||
}
|
||||
for (TriggerListener listener : this.globalTriggerListeners) {
|
||||
ReflectionUtils.invokeMethod(addTriggerListener, target, listener);
|
||||
if (quartz2) {
|
||||
List<?> emptyMatchers = new LinkedList<Object>();
|
||||
ReflectionUtils.invokeMethod(addTriggerListener, target, listener, emptyMatchers);
|
||||
}
|
||||
else {
|
||||
ReflectionUtils.invokeMethod(addTriggerListener, target, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.triggerListeners != null) {
|
||||
|
||||
+1
@@ -30,6 +30,7 @@ import org.springframework.beans.factory.ListableBeanFactory;
|
||||
* triggers and listeners on a given {@link org.quartz.Scheduler} instance.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.8 as well as Quartz 2.0-2.2, as of Spring 4.0.
|
||||
* <b>Note:</b> Quartz 1.x support is deprecated - please upgrade to Quartz 2.0+.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.6
|
||||
|
||||
+11
-15
@@ -43,6 +43,7 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.PropertiesLoaderUtils;
|
||||
import org.springframework.scheduling.SchedulingException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
@@ -75,6 +76,7 @@ import org.springframework.util.CollectionUtils;
|
||||
* Alternatively, you may add transactional advice for the Scheduler itself.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.8 as well as Quartz 2.0-2.2, as of Spring 4.0.
|
||||
* <b>Note:</b> Quartz 1.x support is deprecated - please upgrade to Quartz 2.0+.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 18.02.2004
|
||||
@@ -157,7 +159,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
}
|
||||
|
||||
|
||||
private Class<?> schedulerFactoryClass = StdSchedulerFactory.class;
|
||||
private Class<? extends SchedulerFactory> schedulerFactoryClass = StdSchedulerFactory.class;
|
||||
|
||||
private String schedulerName;
|
||||
|
||||
@@ -173,7 +175,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
private DataSource nonTransactionalDataSource;
|
||||
|
||||
|
||||
private Map<? ,?> schedulerContextMap;
|
||||
private Map<String, ?> schedulerContextMap;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@@ -200,7 +202,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
|
||||
/**
|
||||
* Set the Quartz SchedulerFactory implementation to use.
|
||||
* <p>Default is StdSchedulerFactory, reading in the standard
|
||||
* <p>Default is {@link StdSchedulerFactory}, reading in the standard
|
||||
* {@code quartz.properties} from {@code quartz.jar}.
|
||||
* To use custom Quartz properties, specify the "configLocation"
|
||||
* or "quartzProperties" bean property on this FactoryBean.
|
||||
@@ -208,10 +210,8 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
* @see #setConfigLocation
|
||||
* @see #setQuartzProperties
|
||||
*/
|
||||
public void setSchedulerFactoryClass(Class<?> schedulerFactoryClass) {
|
||||
if (schedulerFactoryClass == null || !SchedulerFactory.class.isAssignableFrom(schedulerFactoryClass)) {
|
||||
throw new IllegalArgumentException("schedulerFactoryClass must implement [org.quartz.SchedulerFactory]");
|
||||
}
|
||||
public void setSchedulerFactoryClass(Class<? extends SchedulerFactory> schedulerFactoryClass) {
|
||||
Assert.isAssignable(SchedulerFactory.class, schedulerFactoryClass);
|
||||
this.schedulerFactoryClass = schedulerFactoryClass;
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
* values (for example Spring-managed beans)
|
||||
* @see JobDetailBean#setJobDataAsMap
|
||||
*/
|
||||
public void setSchedulerContextAsMap(Map<?, ?> schedulerContextAsMap) {
|
||||
public void setSchedulerContextAsMap(Map<String, ?> schedulerContextAsMap) {
|
||||
this.schedulerContextMap = schedulerContextAsMap;
|
||||
}
|
||||
|
||||
@@ -455,10 +455,8 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
this.resourceLoader = this.applicationContext;
|
||||
}
|
||||
|
||||
// Create SchedulerFactory instance.
|
||||
SchedulerFactory schedulerFactory = (SchedulerFactory)
|
||||
BeanUtils.instantiateClass(this.schedulerFactoryClass);
|
||||
|
||||
// Create SchedulerFactory instance...
|
||||
SchedulerFactory schedulerFactory = BeanUtils.instantiateClass(this.schedulerFactoryClass);
|
||||
initSchedulerFactory(schedulerFactory);
|
||||
|
||||
if (this.resourceLoader != null) {
|
||||
@@ -521,9 +519,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
* Load and/or apply Quartz properties to the given SchedulerFactory.
|
||||
* @param schedulerFactory the SchedulerFactory to initialize
|
||||
*/
|
||||
private void initSchedulerFactory(SchedulerFactory schedulerFactory)
|
||||
throws SchedulerException, IOException {
|
||||
|
||||
private void initSchedulerFactory(SchedulerFactory schedulerFactory) throws SchedulerException, IOException {
|
||||
if (!(schedulerFactory instanceof StdSchedulerFactory)) {
|
||||
if (this.configLocation != null || this.quartzProperties != null ||
|
||||
this.taskExecutor != null || this.dataSource != null) {
|
||||
|
||||
+19
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -25,9 +25,12 @@ import org.quartz.simpl.SimpleThreadPool;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.scheduling.SchedulingException;
|
||||
import org.springframework.scheduling.SchedulingTaskExecutor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureTask;
|
||||
|
||||
/**
|
||||
* Subclass of Quartz's SimpleThreadPool that implements Spring's
|
||||
@@ -45,7 +48,7 @@ import org.springframework.util.Assert;
|
||||
* @see SchedulerFactoryBean#setTaskExecutor
|
||||
*/
|
||||
public class SimpleThreadPoolTaskExecutor extends SimpleThreadPool
|
||||
implements SchedulingTaskExecutor, InitializingBean, DisposableBean {
|
||||
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor, InitializingBean, DisposableBean {
|
||||
|
||||
private boolean waitForJobsToCompleteOnShutdown = false;
|
||||
|
||||
@@ -92,6 +95,20 @@ public class SimpleThreadPoolTaskExecutor extends SimpleThreadPool
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<?> submitListenable(Runnable task) {
|
||||
ListenableFutureTask<Object> future = new ListenableFutureTask<Object>(task, null);
|
||||
execute(future);
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
|
||||
ListenableFutureTask<T> future = new ListenableFutureTask<T>(task);
|
||||
execute(future);
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
* This task executor prefers short-lived work units.
|
||||
*/
|
||||
|
||||
+7
-6
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -113,10 +112,12 @@ public class SimpleTriggerBean extends SimpleTrigger
|
||||
* by the TriggerListener implementation.
|
||||
* @see SchedulerFactoryBean#setTriggerListeners
|
||||
* @see org.quartz.TriggerListener#getName
|
||||
* @deprecated as of Spring 4.0, since it only works on Quartz 1.x
|
||||
*/
|
||||
public void setTriggerListenerNames(String[] names) {
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
addTriggerListener(names[i]);
|
||||
@Deprecated
|
||||
public void setTriggerListenerNames(String... names) {
|
||||
for (String name : names) {
|
||||
addTriggerListener(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,14 +157,14 @@ public class SimpleTriggerBean extends SimpleTrigger
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws ParseException {
|
||||
public void afterPropertiesSet() {
|
||||
if (getName() == null) {
|
||||
setName(this.beanName);
|
||||
}
|
||||
if (getGroup() == null) {
|
||||
setGroup(Scheduler.DEFAULT_GROUP);
|
||||
}
|
||||
if (getStartTime() == null) {
|
||||
if (this.startDelay > 0 || getStartTime() == null) {
|
||||
setStartTime(new Date(System.currentTimeMillis() + this.startDelay));
|
||||
}
|
||||
if (this.jobDetail != null) {
|
||||
|
||||
+24
-6
@@ -17,7 +17,6 @@
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -88,6 +87,8 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
|
||||
private int misfireInstruction;
|
||||
|
||||
private String description;
|
||||
|
||||
private String beanName;
|
||||
|
||||
private SimpleTrigger simpleTrigger;
|
||||
@@ -141,10 +142,20 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
this.jobDataMap.putAll(jobDataAsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific start time for the trigger.
|
||||
* <p>Note that a dynamically computed {@link #setStartDelay} specification
|
||||
* overrides a static timestamp set here.
|
||||
*/
|
||||
public void setStartTime(Date startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the start delay in milliseconds.
|
||||
* <p>The start delay is added to the current system time (when the bean starts)
|
||||
* to control the start time of the trigger.
|
||||
* @see #setStartTime
|
||||
*/
|
||||
public void setStartDelay(long startDelay) {
|
||||
Assert.isTrue(startDelay >= 0, "Start delay cannot be negative");
|
||||
@@ -195,6 +206,13 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
this.misfireInstruction = constants.asNumber(constantName).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a textual description with this trigger.
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
@@ -202,7 +220,7 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws ParseException {
|
||||
public void afterPropertiesSet() {
|
||||
if (this.name == null) {
|
||||
this.name = this.beanName;
|
||||
}
|
||||
@@ -212,12 +230,9 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
if (this.jobDetail != null) {
|
||||
this.jobDataMap.put(JobDetailAwareTrigger.JOB_DETAIL_KEY, this.jobDetail);
|
||||
}
|
||||
if (this.startDelay > 0) {
|
||||
if (this.startDelay > 0 || this.startTime == null) {
|
||||
this.startTime = new Date(System.currentTimeMillis() + this.startDelay);
|
||||
}
|
||||
else if (this.startTime == null) {
|
||||
this.startTime = new Date();
|
||||
}
|
||||
|
||||
/*
|
||||
SimpleTriggerImpl sti = new SimpleTriggerImpl();
|
||||
@@ -230,6 +245,7 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
sti.setRepeatCount(this.repeatCount);
|
||||
sti.setPriority(this.priority);
|
||||
sti.setMisfireInstruction(this.misfireInstruction);
|
||||
cti.setDescription(this.description);
|
||||
this.simpleTrigger = sti;
|
||||
*/
|
||||
|
||||
@@ -263,6 +279,7 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
pvs.add("repeatCount", this.repeatCount);
|
||||
pvs.add("priority", this.priority);
|
||||
pvs.add("misfireInstruction", this.misfireInstruction);
|
||||
pvs.add("description", this.description);
|
||||
bw.setPropertyValues(pvs);
|
||||
this.simpleTrigger = (SimpleTrigger) bw.getWrappedInstance();
|
||||
}
|
||||
@@ -282,4 +299,5 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -38,6 +38,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* is by default simply ignored. This is analogous to QuartzJobBean's behavior.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.8 as well as Quartz 2.0-2.2, as of Spring 4.0.
|
||||
* <b>Note:</b> Quartz 1.x support is deprecated - please upgrade to Quartz 2.0+.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
@@ -59,7 +60,7 @@ public class SpringBeanJobFactory extends AdaptableJobFactory implements Schedul
|
||||
* ignored if there is no corresponding property found on the particular
|
||||
* job class (all other unknown properties will still trigger an exception).
|
||||
*/
|
||||
public void setIgnoredUnknownProperties(String[] ignoredUnknownProperties) {
|
||||
public void setIgnoredUnknownProperties(String... ignoredUnknownProperties) {
|
||||
this.ignoredUnknownProperties = ignoredUnknownProperties;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +19,8 @@ package org.springframework.cache;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A manager for a set of {@link Cache}s.
|
||||
* Spring's central cache manager SPI.
|
||||
* Allows for retrieving named {@link Cache} regions.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
@@ -28,14 +29,14 @@ public interface CacheManager {
|
||||
|
||||
/**
|
||||
* Return the cache associated with the given name.
|
||||
* @param name cache identifier (must not be {@code null})
|
||||
* @return associated cache, or {@code null} if none is found
|
||||
* @param name the cache identifier (must not be {@code null})
|
||||
* @return the associated cache, or {@code null} if none found
|
||||
*/
|
||||
Cache getCache(String name);
|
||||
|
||||
/**
|
||||
* Return a collection of the caches known by this cache manager.
|
||||
* @return names of caches known by the cache manager.
|
||||
* Return a collection of the cache names known by this manager.
|
||||
* @return the names of all caches known by the cache manager
|
||||
*/
|
||||
Collection<String> getCacheNames();
|
||||
|
||||
|
||||
+3
-3
@@ -87,16 +87,16 @@ public class ConcurrentMapCache implements Cache {
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
public final String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConcurrentMap<Object, Object> getNativeCache() {
|
||||
public final ConcurrentMap<Object, Object> getNativeCache() {
|
||||
return this.store;
|
||||
}
|
||||
|
||||
public boolean isAllowNullValues() {
|
||||
public final boolean isAllowNullValues() {
|
||||
return this.allowNullValues;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+22
-1
@@ -47,6 +47,8 @@ public class ConcurrentMapCacheManager implements CacheManager {
|
||||
|
||||
private boolean dynamic = true;
|
||||
|
||||
private boolean allowNullValues = true;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a dynamic ConcurrentMapCacheManager,
|
||||
@@ -78,6 +80,25 @@ public class ConcurrentMapCacheManager implements CacheManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether to accept and convert {@code null} values for all caches
|
||||
* in this cache manager.
|
||||
* <p>Default is "true", despite ConcurrentHashMap itself not supporting {@code null}
|
||||
* values. An internal holder object will be used to store user-level {@code null}s.
|
||||
*/
|
||||
public void setAllowNullValues(boolean allowNullValues) {
|
||||
this.allowNullValues = allowNullValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this cache manager accepts and converts {@code null} values
|
||||
* for all of its caches.
|
||||
*/
|
||||
public boolean isAllowNullValues() {
|
||||
return this.allowNullValues;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<String> getCacheNames() {
|
||||
return Collections.unmodifiableSet(this.cacheMap.keySet());
|
||||
@@ -104,7 +125,7 @@ public class ConcurrentMapCacheManager implements CacheManager {
|
||||
* @return the ConcurrentMapCache (or a decorator thereof)
|
||||
*/
|
||||
protected Cache createConcurrentMapCache(String name) {
|
||||
return new ConcurrentMapCache(name);
|
||||
return new ConcurrentMapCache(name, isAllowNullValues());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-10
@@ -25,6 +25,7 @@ import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.framework.AopProxyUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cache.Cache;
|
||||
@@ -37,6 +38,7 @@ import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -114,7 +116,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
|
||||
/**
|
||||
* Set the KeyGenerator for this cache aspect.
|
||||
* Default is {@link DefaultKeyGenerator}.
|
||||
* The default is a {@link SimpleKeyGenerator}.
|
||||
*/
|
||||
public void setKeyGenerator(KeyGenerator keyGenerator) {
|
||||
this.keyGenerator = keyGenerator;
|
||||
@@ -249,8 +251,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
}
|
||||
|
||||
private void logInvalidating(CacheOperationContext context, CacheEvictOperation operation, Object key) {
|
||||
if (this.logger.isTraceEnabled()) {
|
||||
this.logger.trace("Invalidating " + (key == null ? "entire cache" : "cache key " + key) +
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Invalidating " + (key != null ? "cache key [" + key + "]" : "entire cache") +
|
||||
" for operation " + operation + " on method " + context.method);
|
||||
}
|
||||
}
|
||||
@@ -302,8 +304,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
|
||||
private boolean isConditionPassing(CacheOperationContext context, Object result) {
|
||||
boolean passing = context.isConditionPassing(result);
|
||||
if (!passing && this.logger.isTraceEnabled()) {
|
||||
this.logger.trace("Cache condition failed on method " + context.method + " for operation " + context.operation);
|
||||
if (!passing && logger.isTraceEnabled()) {
|
||||
logger.trace("Cache condition failed on method " + context.method + " for operation " + context.operation);
|
||||
}
|
||||
return passing;
|
||||
}
|
||||
@@ -312,8 +314,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
Object key = context.generateKey(result);
|
||||
Assert.notNull(key, "Null key returned for cache operation (maybe you are using named params " +
|
||||
"on classes without debug info?) " + context.operation);
|
||||
if (this.logger.isTraceEnabled()) {
|
||||
this.logger.trace("Computed cache key " + key + " for operation " + context.operation);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Computed cache key " + key + " for operation " + context.operation);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
@@ -334,7 +336,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
Method method, Object[] args, Object target, Class<?> targetClass) {
|
||||
|
||||
for (CacheOperation operation : operations) {
|
||||
this.contexts.add(operation.getClass(), new CacheOperationContext(operation, method, args, target, targetClass));
|
||||
this.contexts.add(operation.getClass(), getOperationContext(operation, method, args, target, targetClass));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,7 +375,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
if (!method.isVarArgs()) {
|
||||
return args;
|
||||
}
|
||||
Object[] varArgs = (Object[]) args[args.length - 1];
|
||||
Object[] varArgs = ObjectUtils.toObjectArray(args[args.length - 1]);
|
||||
Object[] combinedArgs = new Object[args.length - 1 + varArgs.length];
|
||||
System.arraycopy(args, 0, combinedArgs, 0, args.length - 1);
|
||||
System.arraycopy(varArgs, 0, combinedArgs, args.length - 1, varArgs.length);
|
||||
@@ -416,7 +418,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
}
|
||||
|
||||
private EvaluationContext createEvaluationContext(Object result) {
|
||||
return evaluator.createEvaluationContext(this.caches, this.method, this.args, this.target, this.targetClass, result);
|
||||
return evaluator.createEvaluationContext(
|
||||
this.caches, this.method, this.args, this.target, this.targetClass, result);
|
||||
}
|
||||
|
||||
protected Collection<? extends Cache> getCaches() {
|
||||
|
||||
Vendored
+1
-1
@@ -24,7 +24,7 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Class describing the root object used during the expression evaluation.
|
||||
*
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
|
||||
+44
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,42 +17,72 @@
|
||||
package org.springframework.cache.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Composite {@link CacheManager} implementation that iterates
|
||||
* over a given collection of {@link CacheManager} instances.
|
||||
* Composite {@link CacheManager} implementation that iterates over
|
||||
* a given collection of delegate {@link CacheManager} instances.
|
||||
*
|
||||
* Allows {@link NoOpCacheManager} to be automatically added to the list for handling
|
||||
* the cache declarations without a backing store.
|
||||
* <p>Allows {@link NoOpCacheManager} to be automatically added to the end of
|
||||
* the list for handling cache declarations without a backing store. Otherwise,
|
||||
* any custom {@link CacheManager} may play that role of the last delegate as
|
||||
* well, lazily creating cache regions for any requested name.
|
||||
*
|
||||
* <p>Note: Regular CacheManagers that this composite manager delegates to need
|
||||
* to return {@code null} from {@link #getCache(String)} if they are unaware of
|
||||
* the specified cache name, allowing for iteration to the next delegate in line.
|
||||
* However, most {@link CacheManager} implementations fall back to lazy creation
|
||||
* of named caches once requested; check out the specific configuration details
|
||||
* for a 'static' mode with fixed cache names, if available.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see #setFallbackToNoOpCache
|
||||
* @see org.springframework.cache.concurrent.ConcurrentMapCacheManager#setCacheNames
|
||||
*/
|
||||
public class CompositeCacheManager implements InitializingBean, CacheManager {
|
||||
public class CompositeCacheManager implements CacheManager, InitializingBean {
|
||||
|
||||
private List<CacheManager> cacheManagers;
|
||||
private final List<CacheManager> cacheManagers = new ArrayList<CacheManager>();
|
||||
|
||||
private boolean fallbackToNoOpCache = false;
|
||||
|
||||
|
||||
/**
|
||||
* Construct an empty CompositeCacheManager, with delegate CacheManagers to
|
||||
* be added via the {@link #setCacheManagers "cacheManagers"} property.
|
||||
*/
|
||||
public CompositeCacheManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a CompositeCacheManager from the given delegate CacheManagers.
|
||||
* @param cacheManagers the CacheManagers to delegate to
|
||||
*/
|
||||
public CompositeCacheManager(CacheManager... cacheManagers) {
|
||||
setCacheManagers(Arrays.asList(cacheManagers));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify the CacheManagers to delegate to.
|
||||
*/
|
||||
public void setCacheManagers(Collection<CacheManager> cacheManagers) {
|
||||
Assert.notEmpty(cacheManagers, "cacheManagers Collection must not be empty");
|
||||
this.cacheManagers = new ArrayList<CacheManager>();
|
||||
this.cacheManagers.addAll(cacheManagers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate whether a {@link NoOpCacheManager} should be added at the end of the manager lists.
|
||||
* In this case, any {@code getCache} requests not handled by the configured cache managers will
|
||||
* Indicate whether a {@link NoOpCacheManager} should be added at the end of the delegate list.
|
||||
* In this case, any {@code getCache} requests not handled by the configured CacheManagers will
|
||||
* be automatically handled by the {@link NoOpCacheManager} (and hence never return {@code null}).
|
||||
*/
|
||||
public void setFallbackToNoOpCache(boolean fallbackToNoOpCache) {
|
||||
@@ -80,11 +110,11 @@ public class CompositeCacheManager implements InitializingBean, CacheManager {
|
||||
|
||||
@Override
|
||||
public Collection<String> getCacheNames() {
|
||||
List<String> names = new ArrayList<String>();
|
||||
Set<String> names = new LinkedHashSet<String>();
|
||||
for (CacheManager manager : this.cacheManagers) {
|
||||
names.addAll(manager.getCacheNames());
|
||||
}
|
||||
return Collections.unmodifiableList(names);
|
||||
return Collections.unmodifiableSet(names);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-9
@@ -89,13 +89,16 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
|
||||
for (String type : types) {
|
||||
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
|
||||
if (isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
|
||||
String value = (String) attributes.get("value");
|
||||
if (StringUtils.hasLength(value)) {
|
||||
if (beanName != null && !value.equals(beanName)) {
|
||||
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
|
||||
"component names: '" + beanName + "' versus '" + value + "'");
|
||||
Object value = attributes.get("value");
|
||||
if (value instanceof String) {
|
||||
String strVal = (String) value;
|
||||
if (StringUtils.hasLength(strVal)) {
|
||||
if (beanName != null && !strVal.equals(beanName)) {
|
||||
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
|
||||
"component names: '" + beanName + "' versus '" + strVal + "'");
|
||||
}
|
||||
beanName = strVal;
|
||||
}
|
||||
beanName = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,9 +121,7 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
|
||||
annotationType.equals("javax.annotation.ManagedBean") ||
|
||||
annotationType.equals("javax.inject.Named");
|
||||
|
||||
return (isStereotype && attributes != null &&
|
||||
attributes.containsKey("value") &&
|
||||
attributes.get("value") instanceof String);
|
||||
return (isStereotype && attributes != null && attributes.containsKey("value"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -315,10 +315,10 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
// Fall back to class name as cache key, for backwards compatibility with custom callers.
|
||||
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
|
||||
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
|
||||
if (metadata == null) {
|
||||
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
|
||||
synchronized (this.injectionMetadataCache) {
|
||||
metadata = this.injectionMetadataCache.get(cacheKey);
|
||||
if (metadata == null) {
|
||||
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
|
||||
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
Class<?> targetClass = clazz;
|
||||
|
||||
|
||||
+57
-41
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,6 +34,7 @@ import org.springframework.beans.factory.support.SimpleInstantiationStrategy;
|
||||
import org.springframework.cglib.core.ClassGenerator;
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.cglib.core.DefaultGeneratorStrategy;
|
||||
import org.springframework.cglib.core.SpringNamingPolicy;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.CallbackFilter;
|
||||
import org.springframework.cglib.proxy.Enhancer;
|
||||
@@ -47,8 +48,13 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Enhances {@link Configuration} classes by generating a CGLIB subclass capable of
|
||||
* interacting with the Spring container to respect bean semantics.
|
||||
* Enhances {@link Configuration} classes by generating a CGLIB subclass which
|
||||
* interacts with the Spring container to respect bean scoping semantics for
|
||||
* {@code @Bean} methods. Each such {@code @Bean} method will be overridden in
|
||||
* the generated subclass, only delegating to the actual {@code @Bean} method
|
||||
* implementation if the container actually requests the construction of a new
|
||||
* instance. Otherwise, a call to such an {@code @Bean} method serves as a
|
||||
* reference back to the container, obtaining the corresponding bean by name.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
@@ -67,6 +73,8 @@ class ConfigurationClassEnhancer {
|
||||
|
||||
private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);
|
||||
|
||||
private static final DefaultGeneratorStrategy GENERATOR_STRATEGY = new BeanFactoryAwareGeneratorStrategy();
|
||||
|
||||
private static final String BEAN_FACTORY_FIELD = "$$beanFactory";
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ConfigurationClassEnhancer.class);
|
||||
@@ -105,22 +113,10 @@ class ConfigurationClassEnhancer {
|
||||
enhancer.setSuperclass(superclass);
|
||||
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
|
||||
enhancer.setUseFactory(false);
|
||||
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
||||
enhancer.setStrategy(GENERATOR_STRATEGY);
|
||||
enhancer.setCallbackFilter(CALLBACK_FILTER);
|
||||
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
|
||||
enhancer.setStrategy(new DefaultGeneratorStrategy() {
|
||||
@Override
|
||||
protected ClassGenerator transform(ClassGenerator cg) throws Exception {
|
||||
ClassEmitterTransformer transformer = new ClassEmitterTransformer() {
|
||||
@Override
|
||||
public void end_class() {
|
||||
declare_field(Constants.ACC_PUBLIC, BEAN_FACTORY_FIELD,
|
||||
Type.getType(BeanFactory.class), null);
|
||||
super.end_class();
|
||||
}
|
||||
};
|
||||
return new TransformingClassGenerator(cg, transformer);
|
||||
}
|
||||
});
|
||||
return enhancer;
|
||||
}
|
||||
|
||||
@@ -200,37 +196,27 @@ class ConfigurationClassEnhancer {
|
||||
|
||||
|
||||
/**
|
||||
* Intercepts the invocation of any {@link DisposableBean#destroy()} on @Configuration
|
||||
* class instances for the purpose of de-registering CGLIB callbacks. This helps avoid
|
||||
* garbage collection issues. See SPR-7901.
|
||||
* @see EnhancedConfiguration
|
||||
* Custom extension of CGLIB's DefaultGeneratorStrategy, introducing a {@link BeanFactory} field.
|
||||
*/
|
||||
private static class DisposableBeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {
|
||||
private static class BeanFactoryAwareGeneratorStrategy extends DefaultGeneratorStrategy {
|
||||
|
||||
@Override
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
||||
Enhancer.registerStaticCallbacks(obj.getClass(), null);
|
||||
// Does the actual (non-CGLIB) superclass actually implement DisposableBean?
|
||||
// If so, call its dispose() method. If not, just exit.
|
||||
if (DisposableBean.class.isAssignableFrom(obj.getClass().getSuperclass())) {
|
||||
return proxy.invokeSuper(obj, args);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(Method candidateMethod) {
|
||||
return candidateMethod.getName().equals("destroy") &&
|
||||
candidateMethod.getParameterTypes().length == 0 &&
|
||||
DisposableBean.class.isAssignableFrom(candidateMethod.getDeclaringClass());
|
||||
protected ClassGenerator transform(ClassGenerator cg) throws Exception {
|
||||
ClassEmitterTransformer transformer = new ClassEmitterTransformer() {
|
||||
@Override
|
||||
public void end_class() {
|
||||
declare_field(Constants.ACC_PUBLIC, BEAN_FACTORY_FIELD, Type.getType(BeanFactory.class), null);
|
||||
super.end_class();
|
||||
}
|
||||
};
|
||||
return new TransformingClassGenerator(cg, transformer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Intercepts the invocation of any
|
||||
* {@link BeanFactoryAware#setBeanFactory(BeanFactory)} on {@code @Configuration}
|
||||
* class instances for the purpose of recording the {@link BeanFactory}.
|
||||
* Intercepts the invocation of any {@link BeanFactoryAware#setBeanFactory(BeanFactory)} on
|
||||
* {@code @Configuration} class instances for the purpose of recording the {@link BeanFactory}.
|
||||
* @see EnhancedConfiguration
|
||||
*/
|
||||
private static class BeanFactoryAwareMethodInterceptor implements MethodInterceptor, ConditionalCallback {
|
||||
@@ -387,6 +373,7 @@ class ConfigurationClassEnhancer {
|
||||
Enhancer enhancer = new Enhancer();
|
||||
enhancer.setSuperclass(fbClass);
|
||||
enhancer.setUseFactory(false);
|
||||
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
||||
enhancer.setCallback(new MethodInterceptor() {
|
||||
@Override
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
||||
@@ -404,7 +391,8 @@ class ConfigurationClassEnhancer {
|
||||
Assert.state(field != null, "Unable to find generated bean factory field");
|
||||
Object beanFactory = ReflectionUtils.getField(field, enhancedConfigInstance);
|
||||
Assert.state(beanFactory != null, "BeanFactory has not been injected into @Configuration class");
|
||||
Assert.state(beanFactory instanceof ConfigurableBeanFactory, "Injected BeanFactory is not a ConfigurableBeanFactory");
|
||||
Assert.state(beanFactory instanceof ConfigurableBeanFactory,
|
||||
"Injected BeanFactory is not a ConfigurableBeanFactory");
|
||||
return (ConfigurableBeanFactory) beanFactory;
|
||||
}
|
||||
|
||||
@@ -414,4 +402,32 @@ class ConfigurationClassEnhancer {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Intercepts the invocation of any {@link DisposableBean#destroy()} on @Configuration
|
||||
* class instances for the purpose of de-registering CGLIB callbacks. This helps avoid
|
||||
* garbage collection issues. See SPR-7901.
|
||||
* @see EnhancedConfiguration
|
||||
*/
|
||||
private static class DisposableBeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {
|
||||
|
||||
@Override
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
||||
Enhancer.registerStaticCallbacks(obj.getClass(), null);
|
||||
// Does the actual (non-CGLIB) superclass actually implement DisposableBean?
|
||||
// If so, call its dispose() method. If not, just exit.
|
||||
if (DisposableBean.class.isAssignableFrom(obj.getClass().getSuperclass())) {
|
||||
return proxy.invokeSuper(obj, args);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(Method candidateMethod) {
|
||||
return candidateMethod.getName().equals("destroy") &&
|
||||
candidateMethod.getParameterTypes().length == 0 &&
|
||||
DisposableBean.class.isAssignableFrom(candidateMethod.getDeclaringClass());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.
|
||||
@@ -19,9 +19,9 @@ package org.springframework.context.annotation;
|
||||
/**
|
||||
* Enumerates the various scoped-proxy options.
|
||||
*
|
||||
* <p>For a fuller discussion of exactly what a scoped-proxy is, see that
|
||||
* section of the Spring reference documentation entitled 'Scoped beans as
|
||||
* dependencies'.
|
||||
* <p>For a more complete discussion of exactly what a scoped proxy is, see the
|
||||
* section of the Spring reference documentation entitled '<em>Scoped beans as
|
||||
* dependencies</em>'.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 2.5
|
||||
@@ -51,8 +51,8 @@ public enum ScopedProxyMode {
|
||||
INTERFACES,
|
||||
|
||||
/**
|
||||
* Create a class-based proxy (requires CGLIB).
|
||||
* Create a class-based proxy (uses CGLIB).
|
||||
*/
|
||||
TARGET_CLASS
|
||||
TARGET_CLASS;
|
||||
|
||||
}
|
||||
|
||||
+5
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -33,7 +33,7 @@ public class EnvironmentAccessor implements PropertyAccessor {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getSpecificTargetClasses() {
|
||||
return new Class<?>[] { Environment.class };
|
||||
return new Class<?>[] {Environment.class};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,12 +51,11 @@ public class EnvironmentAccessor implements PropertyAccessor {
|
||||
*/
|
||||
@Override
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return new TypedValue(((Environment)target).getProperty(name));
|
||||
return new TypedValue(((Environment) target).getProperty(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read only.
|
||||
* @return false
|
||||
* Read-only: returns {@code false}.
|
||||
*/
|
||||
@Override
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
@@ -64,7 +63,7 @@ public class EnvironmentAccessor implements PropertyAccessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Read only. No-op.
|
||||
* Read-only: no-op.
|
||||
*/
|
||||
@Override
|
||||
public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
|
||||
|
||||
+16
-8
@@ -36,9 +36,10 @@ import org.springframework.core.io.Resource;
|
||||
*
|
||||
* <p>Consider this as the equivalent of {@link GenericXmlApplicationContext} for
|
||||
* Groovy bean definitions. The main difference is that, within a Groovy script,
|
||||
* the context can be used with an inline bean definition closure like as follows:
|
||||
* the context can be used with an inline bean definition closure as follows:
|
||||
*
|
||||
* <pre>import org.hibernate.SessionFactory
|
||||
* <pre class="code">
|
||||
* import org.hibernate.SessionFactory
|
||||
* import org.apache.commons.dbcp.BasicDataSource
|
||||
*
|
||||
* def context = new GenericGroovyApplicationContext()
|
||||
@@ -59,12 +60,14 @@ import org.springframework.core.io.Resource;
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* context.refresh()</pre>
|
||||
* context.refresh()
|
||||
* </pre>
|
||||
*
|
||||
* <p>Alternatively, load a Groovy bean definition script like the following
|
||||
* from an external resource (e.g. an "applicationContext.groovy" file):
|
||||
*
|
||||
* <pre>import org.hibernate.SessionFactory
|
||||
* <pre class="code">
|
||||
* import org.hibernate.SessionFactory
|
||||
* import org.apache.commons.dbcp.BasicDataSource
|
||||
*
|
||||
* beans {
|
||||
@@ -83,18 +86,23 @@ import org.springframework.core.io.Resource;
|
||||
* dataSource = dataSource
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>With the following Java code creating the {@code GenericGroovyApplicationContext}
|
||||
* (potentially using Ant-style '*'/'**' location patterns):
|
||||
*
|
||||
* <pre>GenericGroovyApplicationContext context = new GenericGroovyApplicationContext();
|
||||
* <pre class="code">
|
||||
* GenericGroovyApplicationContext context = new GenericGroovyApplicationContext();
|
||||
* context.load("org/myapp/applicationContext.groovy");
|
||||
* context.refresh();</pre>
|
||||
* context.refresh();
|
||||
* </pre>
|
||||
*
|
||||
* <p>Or even more concise, provided that no extra configuration is needed:
|
||||
*
|
||||
* <pre>ApplicationContext context = new GenericGroovyApplicationContext("org/myapp/applicationContext.groovy");</pre>
|
||||
* <pre class="code">
|
||||
* ApplicationContext context = new GenericGroovyApplicationContext("org/myapp/applicationContext.groovy");
|
||||
* </pre>
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Jeff Brown
|
||||
|
||||
+30
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,6 +25,7 @@ import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
@@ -40,7 +41,7 @@ import org.springframework.util.StringUtils;
|
||||
* (driven by the {@value #MBEAN_DOMAIN_PROPERTY_NAME} environment property).
|
||||
*
|
||||
* <p>Note: This feature is still in beta and primarily designed for use with
|
||||
* Spring Tool Suite 3.1.
|
||||
* Spring Tool Suite 3.1 and higher.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.2
|
||||
@@ -118,6 +119,17 @@ public class LiveBeansView implements LiveBeansViewMBean, ApplicationContextAwar
|
||||
return generateJson(contexts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all applicable ApplicationContexts for the current application.
|
||||
* <p>Called if no specific ApplicationContext has been set for this LiveBeansView.
|
||||
* @return the set of ApplicationContexts
|
||||
*/
|
||||
protected Set<ConfigurableApplicationContext> findApplicationContexts() {
|
||||
synchronized (applicationContexts) {
|
||||
return new LinkedHashSet<ConfigurableApplicationContext>(applicationContexts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually generate a JSON snapshot of the beans in the given ApplicationContexts.
|
||||
* <p>This implementation doesn't use any JSON parsing libraries in order to avoid
|
||||
@@ -143,11 +155,13 @@ public class LiveBeansView implements LiveBeansViewMBean, ApplicationContextAwar
|
||||
result.append("\"beans\": [\n");
|
||||
ConfigurableListableBeanFactory bf = context.getBeanFactory();
|
||||
String[] beanNames = bf.getBeanDefinitionNames();
|
||||
for (int i = 0; i < beanNames.length; i++) {
|
||||
String beanName = beanNames[i];
|
||||
boolean elementAppended = false;
|
||||
for (String beanName : beanNames) {
|
||||
BeanDefinition bd = bf.getBeanDefinition(beanName);
|
||||
if (bd.getRole() != BeanDefinition.ROLE_INFRASTRUCTURE &&
|
||||
(!bd.isLazyInit() || bf.containsSingleton(beanName))) {
|
||||
if (isBeanEligible(beanName, bd, bf)) {
|
||||
if (elementAppended) {
|
||||
result.append(",\n");
|
||||
}
|
||||
result.append("{\n\"bean\": \"").append(beanName).append("\",\n");
|
||||
String scope = bd.getScope();
|
||||
if (!StringUtils.hasText(scope)) {
|
||||
@@ -173,9 +187,7 @@ public class LiveBeansView implements LiveBeansViewMBean, ApplicationContextAwar
|
||||
result.append("\"");
|
||||
}
|
||||
result.append("]\n}");
|
||||
if (i < beanNames.length - 1) {
|
||||
result.append(",\n");
|
||||
}
|
||||
elementAppended = true;
|
||||
}
|
||||
}
|
||||
result.append("]\n");
|
||||
@@ -189,14 +201,16 @@ public class LiveBeansView implements LiveBeansViewMBean, ApplicationContextAwar
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all applicable ApplicationContexts for the current application.
|
||||
* <p>Called if no specific ApplicationContext has been set for this LiveBeansView.
|
||||
* @return the set of ApplicationContexts
|
||||
* Determine whether the specified bean is eligible for inclusion in the
|
||||
* LiveBeansView JSON snapshot.
|
||||
* @param beanName the name of the bean
|
||||
* @param bd the corresponding bean definition
|
||||
* @param bf the containing bean factory
|
||||
* @return {@code true} if the bean is to be included; {@code false} otherwise
|
||||
*/
|
||||
protected Set<ConfigurableApplicationContext> findApplicationContexts() {
|
||||
synchronized (applicationContexts) {
|
||||
return new LinkedHashSet<ConfigurableApplicationContext>(applicationContexts);
|
||||
}
|
||||
protected boolean isBeanEligible(String beanName, BeanDefinition bd, ConfigurableBeanFactory bf) {
|
||||
return (bd.getRole() != BeanDefinition.ROLE_INFRASTRUCTURE &&
|
||||
(!bd.isLazyInit() || bf.containsSingleton(beanName)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,14 +27,17 @@ import org.springframework.beans.factory.config.Scope;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
|
||||
/**
|
||||
* Thread-backed {@link Scope} implementation.
|
||||
* A simple thread-backed {@link Scope} implementation.
|
||||
*
|
||||
* <p><strong>Note</strong> that the {@code SimpleThreadScope} <em>does not clean up any objects</em> associated
|
||||
* with it. As such, it's typically preferable to use the {@link org.springframework.web.context.request.RequestScope}
|
||||
* in Web environments.
|
||||
* <p><strong>Note:</strong> {@code SimpleThreadScope} <em>does not clean up
|
||||
* any objects</em> associated with it. As such, it is typically preferable to
|
||||
* use {@link org.springframework.web.context.request.RequestScope RequestScope}
|
||||
* in web environments.
|
||||
*
|
||||
* <p>For a implementation of a thread-based {@code Scope} with support for destruction callbacks, refer to <a
|
||||
* href="http://www.springbyexample.org/twiki/bin/view/Example/CustomThreadScopeModule">this module</a>.
|
||||
* <p>For an implementation of a thread-based {@code Scope} with support for
|
||||
* destruction callbacks, refer to the
|
||||
* <a href="http://www.springbyexample.org/examples/custom-thread-scope-module.html">
|
||||
* Spring by Example Custom Thread Scope Module</a>.
|
||||
*
|
||||
* <p>Thanks to Eugene Kuleshov for submitting the original prototype for a thread scope!
|
||||
*
|
||||
@@ -55,9 +58,10 @@ public class SimpleThreadScope implements Scope {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
public Object get(String name, ObjectFactory<?> objectFactory) {
|
||||
Map<String, Object> scope = threadScope.get();
|
||||
Map<String, Object> scope = this.threadScope.get();
|
||||
Object object = scope.get(name);
|
||||
if (object == null) {
|
||||
object = objectFactory.getObject();
|
||||
@@ -68,14 +72,14 @@ public class SimpleThreadScope implements Scope {
|
||||
|
||||
@Override
|
||||
public Object remove(String name) {
|
||||
Map<String, Object> scope = threadScope.get();
|
||||
Map<String, Object> scope = this.threadScope.get();
|
||||
return scope.remove(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerDestructionCallback(String name, Runnable callback) {
|
||||
logger.warn("SimpleThreadScope does not support descruction callbacks. " +
|
||||
"Consider using a RequestScope in a Web environment.");
|
||||
logger.warn("SimpleThreadScope does not support destruction callbacks. " +
|
||||
"Consider using RequestScope in a web environment.");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,7 +37,7 @@ public interface AnnotationFormatterFactory<A extends Annotation> {
|
||||
|
||||
/**
|
||||
* Get the Printer to print the value of a field of {@code fieldType} annotated with {@code annotation}.
|
||||
* If the type <T> the printer accepts is not assignable to {@code fieldType}, a coersion from {@code fieldType} to <T> will be attempted before the Printer is invoked.
|
||||
* If the type <T> the printer accepts is not assignable to {@code fieldType}, a coercion from {@code fieldType} to <T> will be attempted before the Printer is invoked.
|
||||
* @param annotation the annotation instance
|
||||
* @param fieldType the type of field that was annotated
|
||||
* @return the printer
|
||||
@@ -46,7 +46,7 @@ public interface AnnotationFormatterFactory<A extends Annotation> {
|
||||
|
||||
/**
|
||||
* Get the Parser to parse a submitted value for a field of {@code fieldType} annotated with {@code annotation}.
|
||||
* If the object the parser returns is not assignable to {@code fieldType}, a coersion to {@code fieldType} will be attempted before the field is set.
|
||||
* If the object the parser returns is not assignable to {@code fieldType}, a coercion to {@code fieldType} will be attempted before the field is set.
|
||||
* @param annotation the annotation instance
|
||||
* @param fieldType the type of field that was annotated
|
||||
* @return the parser
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -41,9 +41,9 @@ public interface FormatterRegistry extends ConverterRegistry {
|
||||
/**
|
||||
* Adds a Formatter to format fields of the given type.
|
||||
* <p>On print, if the Formatter's type T is declared and {@code fieldType} is not assignable to T,
|
||||
* a coersion to T will be attempted before delegating to {@code formatter} to print a field value.
|
||||
* a coercion to T will be attempted before delegating to {@code formatter} to print a field value.
|
||||
* On parse, if the parsed object returned by {@code formatter} is not assignable to the runtime field type,
|
||||
* a coersion to the field type will be attempted before returning the parsed field value.
|
||||
* a coercion to the field type will be attempted before returning the parsed field value.
|
||||
* @param fieldType the field type to format
|
||||
* @param formatter the formatter to add
|
||||
*/
|
||||
@@ -54,9 +54,9 @@ public interface FormatterRegistry extends ConverterRegistry {
|
||||
* The formatter will delegate to the specified {@code printer} for printing
|
||||
* and the specified {@code parser} for parsing.
|
||||
* <p>On print, if the Printer's type T is declared and {@code fieldType} is not assignable to T,
|
||||
* a coersion to T will be attempted before delegating to {@code printer} to print a field value.
|
||||
* a coercion to T will be attempted before delegating to {@code printer} to print a field value.
|
||||
* On parse, if the object returned by the Parser is not assignable to the runtime field type,
|
||||
* a coersion to the field type will be attempted before returning the parsed field value.
|
||||
* a coercion to the field type will be attempted before returning the parsed field value.
|
||||
* @param fieldType the field type to format
|
||||
* @param printer the printing part of the formatter
|
||||
* @param parser the parsing part of the formatter
|
||||
|
||||
+5
-5
@@ -60,7 +60,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
|
||||
|
||||
// In order to retain back compatibility we only register Date/Calendar
|
||||
// types when a user defined formatter is specified (see SPR-10105)
|
||||
if(this.dateFormatter != null) {
|
||||
if (this.dateFormatter != null) {
|
||||
registry.addFormatter(this.dateFormatter);
|
||||
registry.addFormatterForFieldType(Calendar.class, this.dateFormatter);
|
||||
}
|
||||
@@ -113,7 +113,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
|
||||
|
||||
@Override
|
||||
public Long convert(Calendar source) {
|
||||
return source.getTime().getTime();
|
||||
return source.getTimeInMillis();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,11 +129,11 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
|
||||
|
||||
private static class LongToCalendarConverter implements Converter<Long, Calendar> {
|
||||
|
||||
private final DateToCalendarConverter dateToCalendarConverter = new DateToCalendarConverter();
|
||||
|
||||
@Override
|
||||
public Calendar convert(Long source) {
|
||||
return this.dateToCalendarConverter.convert(new Date(source));
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(source);
|
||||
return calendar;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user