Compare commits

...

62 Commits

Author SHA1 Message Date
Spring Buildmaster 7482cf9021 Release version 3.2.3.RELEASE 2013-05-20 10:18:41 -07:00
Rob Winch 404671416a Update BuildTests to verify JDK 1.6
Issue: SPR-10569
2013-05-20 10:37:33 -05:00
Phillip Webb 260eafc819 Enforce JDK version on CI server
Add a test to ensure that the CI server does not accidentally build
with the wrong JDK version.

Issue: SPR-10569
2013-05-16 17:14:03 -07:00
Juergen Hoeller ef8b5763e6 Final addition to 3.2.3 changelog 2013-05-16 19:31:57 +02:00
Juergen Hoeller 6b89af824d Consistent detection of Order annotation in superclasses and interfaces
Issue: SPR-10514
(cherry picked from commit 814d24e)
2013-05-16 18:07:00 +02:00
Juergen Hoeller 86b4b2ef23 Consistent use of Class<?> in Assert
(cherry picked from commit 16548d2)
2013-05-16 16:11:30 +02:00
Juergen Hoeller faa8430fd7 Avoid NPE in ContextLoader when dealing with an untyped ApplicationContextInitializer
Issue: SPR-10449
(cherry picked from commit a19c976)
2013-05-16 16:11:25 +02:00
Juergen Hoeller 76f870caca Final preparations for 3.2.3 release 2013-05-16 14:50:03 +02:00
Juergen Hoeller 615315728b Fixed BeanPropertyRowMapper to only prefix actual upper-case letters with underscores
Issue: SPR-10547
(cherry picked from commit c8b071c)
2013-05-16 14:34:44 +02:00
Juergen Hoeller 115442242f Replaced Map synchronization with ConcurrentHashMap to avoid session access deadlocks
Issue: SPR-10436
(cherry picked from commit cd3d0c3)
2013-05-16 14:34:38 +02:00
Juergen Hoeller 10c0e8af01 Final changelog entries for 3.2.3 2013-05-16 00:17:00 +02:00
Juergen Hoeller b6e20a4cc9 Introduced "jsonPrefix" bean property
This change involves a modification of the "writeContent" template method to include the "jsonPrefix" String instead of the "prefixJson" boolean flag. Since said template method has only been introduced in 3.2.2, this change should hopefully not be a problem.

Issue: SPR-10567
(cherry picked from commit 28164b4)
2013-05-16 00:02:31 +02:00
Juergen Hoeller a8adec7673 Avoid unnecessary creation of default StandardEnvironment instances
Issue: SPR-10568
(cherry picked from commit 7e01578)
2013-05-15 23:59:29 +02:00
Juergen Hoeller 2ae61c503e Further changelog entries for 3.2.3 2013-05-15 17:04:34 +02:00
Juergen Hoeller c2b2f30669 Polishing 2013-05-15 16:57:57 +02:00
Juergen Hoeller 239a7cd85f Fixed type detection to avoid reuse of parent bean's targetType on child definition merge
Issue: SPR-10374
(cherry picked from commit 070103b)
2013-05-15 16:42:28 +02:00
Juergen Hoeller 6e4317ebfb Properly handle knownSuperclasses in case of an overridden ConfigurationClass
Issue: SPR-10546
2013-05-15 13:47:03 +02:00
Juergen Hoeller 325d8834e3 Polishing 2013-05-15 11:34:58 +02:00
Juergen Hoeller 0c76cb7e80 Clarified that CronTrigger never schedules overlapping executions
Issue: SPR-10556
(cherry picked from commit 5dbbd8f)
2013-05-15 11:34:57 +02:00
Rob Winch 940011e233 Ensure Parent ConfigurationClass loaded on overrides
Previously ConfigurationClassParser could override a nested
@Configuration without consideration of @Bean's defined in parent
classes.

This commit ensures that if the original ConfigurationClass contains
additional bean definitions it is processed again.

Issue: SPR-10546
2013-05-15 11:34:56 +02:00
Rossen Stoyanchev 92bbd8103b Make removal of jsessionid case insensitive
Issue: SPR-10398
2013-05-14 22:07:52 -04:00
Rossen Stoyanchev 9c194699c7 Reinstate removal of semicolon content
Commit 5b1165 was an attempt to leave semicolon content in the URL path
while ignoring it for request mapping purposes. However, it becomes
quite difficult to manage and semicolon content should not always be
ignored (sometimes a semicolon is used as a separator of multiple items
in a path segment, rather than for matrix variables).

This change effectively reverts back to the original approach in 3.2
where a flag on AbstractHandlerMapping can be used to have semicolon
content removed or kept. If kept, path segments with matrix variables
must be represented with a path segment.

The main difference is that by default it is removed everywhere
including the MVC namespace and Java config.

Issue: SPR-10427, SPR-10234
2013-05-14 21:30:59 -04:00
Rossen Stoyanchev 25701ef984 Fix deadlock issue in DeferredResult
Previously DeferredResult locked around the setting of the result
including handling up to the part of submitting a dispatch. This
can cause a deadlock if a timeout occurs at the same time since
the Tomcat timeout thread has its own locking that permits only
one thread to do timeout or dispatch processing.

The fix reduces the locking to cover only the attempt to set the
DeferredResult but not the dispatching.

Issue: SPR-10485
2013-05-14 17:06:00 -04:00
Juergen Hoeller 87ef99df5e Updated changelog for 3.2.3 release 2013-05-14 18:50:39 +02:00
Juergen Hoeller 13ca2752ae Consistent use of Class<?> in core container method signatures
(cherry picked from commit 1461744)
2013-05-14 18:06:12 +02:00
Juergen Hoeller ef363b0f7a Detect a FactoryBean type match even if predictBeanType returned a non-FactoryBean type
This change should be the final piece in the puzzle to let SmartInstantiationAwareBeanPostProcessor's predictBeanType predict a FactoryBean-produced type, effectively as a semantic alternative to its postProcessBeforeInstantiation-related role.

Issue: SPR-10517
(cherry picked from commit bc3e585)
2013-05-14 18:02:49 +02:00
Juergen Hoeller f9db59e730 GenericTypeResolver defensively calls Class.getGenericSuperclass() and consistently uses Class<?>
Issue: SPR-10559
(cherry picked from commit 25e29b8)
2013-05-14 18:01:41 +02:00
Rob Winch 0dcca2304f Remove xdoclint:none for < JDK 8 2013-05-13 11:54:58 -05:00
Rossen Stoyanchev ad272a0c87 Close InputStream in ResourceHttpMessageConverter
Spring 3.2.2 introduced a change to avoid closing the response stream
in HttpMessageConverters (SPR-10095). However, the InputStream of
resources being written, for example as part of a multi-part request
should be closed. This change ensures that.

Issue: SPR-10460
2013-05-10 17:31:48 -04:00
Juergen Hoeller be224e1f30 ServletContextResourcePatternResolver uses encoded jar file location for UrlResource
Adding overloaded constructors for URI specification to UrlResource, as a convenience.

Issue: SPR-10471
(cherry picked from commit 1f0f46f)
2013-05-10 22:13:17 +02:00
Rossen Stoyanchev 4bb0916202 Delay check if pattern ends with slash
This is a minor fix with no actual impact.

Issue: SPR-10504
2013-05-10 12:51:48 -04:00
Rossen Stoyanchev d3eda09c01 Allow treating empty @RequestParam as missing value
If type conversion turns an empty request parameter value (i.e. "") to
null, we should treat it as a missing value. By default the
ConversionService doesn't change empty strings and therefore one must
explicitly convert them to null for example by registering a
StringTrimmerEditor with emptyAsNull=true.

Issue: SPR-10402
2013-05-10 12:51:31 -04:00
Rossen Stoyanchev 399f887128 Add servletRelativeAction form tag attribute
A recent change in FormTag to prepend the context and servlet paths if
not present, causes issues when used in portlet applications.
This change introduces a servletRelativeAction form tag attribute that
must be used for the context and servlet paths to be prepended.

Issue: SPR-10382
2013-05-10 12:51:20 -04:00
Rossen Stoyanchev 4d005b6987 Improve default content type selection
Previously ContentNegotiationManager continued with the next
ContentNegotiationStrategy only if the current one returned an empty
list. Now it also does that if the current ContentNegotiationStrategy
returns "*/*". Since the absence of an Accept header and "*/*" have
the same meaning, this allows a default content type to be used in
either case.

Issue: SPR-10513
2013-05-10 12:51:08 -04:00
Rossen Stoyanchev 532a7a3a02 Invoke global, then local @InitBinder/@ModelAttribute
@InitBinder and @ModelAttribute methods in @ControllerAdvice classes
are now invoked first, allowing any such methods in the @Controller
class to override them.

Issue: SPR-10419
2013-05-10 12:50:24 -04:00
Juergen Hoeller b2d416fd5f Revised ReflectiveMethodResolver to properly handle any kind of List returned from a MethodFilter
Issue: SPR-10392
(cherry picked from commit ad88650)
2013-05-07 22:07:29 +02:00
Juergen Hoeller 7298c3d669 Fixed MockMvc example code
Issue: SPR-10389
(cherry picked from commit 35847ad)
2013-05-07 22:06:51 +02:00
Juergen Hoeller 7bbd38b9e0 Fixed javadoc warnings
Issue: SPR-10373
(cherry picked from commit 1ca943c)
2013-05-07 22:06:33 +02:00
Juergen Hoeller 64d83a550e MappingJackson(2)MessageConverter needs to use bean ClassLoader 2013-05-07 18:22:48 +02:00
Juergen Hoeller 0df1630ab9 Jaxb2Marshaller doesn't need to depend on ResourceLoaderAware
Issue: SPR-10512
(cherry picked from commit 255eab5)
2013-05-03 17:48:12 +02:00
Juergen Hoeller 7cbc115da6 Added "postProcessConfiguration" template method to LocalValidatorFactoryBean; clarified limited compatibility with Hibernate Validator 5.0 2013-05-03 15:19:28 +02:00
Juergen Hoeller b962239e11 Polishing 2013-05-03 13:47:54 +02:00
Juergen Hoeller 872cf6b076 Removed unnecessary HttpUrlTemplate subclass of UriTemplate 2013-05-03 13:38:31 +02:00
Juergen Hoeller b2bd319d47 Polished UriComponents implementation
(cherry picked from commit c3b624d)
2013-05-03 13:23:48 +02:00
Juergen Hoeller e3fa49063e Added note on non-thread-safety of Jackson's DateFormat support 2013-05-02 16:06:51 +02:00
Juergen Hoeller c302efdbbf Further build file updates for alignment with 4.0 build 2013-05-01 22:38:43 +02:00
Juergen Hoeller 12699696f4 Added note on OpenJDK 8 compatibility 2013-05-01 21:45:50 +02:00
Juergen Hoeller c4f2566070 Allow for building and testing the 3.2.x line against OpenJDK 8 2013-05-01 21:39:51 +02:00
Juergen Hoeller 6458643f15 Updated 3.2.3 changelog 2013-04-30 23:57:15 +02:00
Juergen Hoeller 2145545e69 Ignore failing TopLink tests (not worth messing with since TopLink is deprecated anyway) 2013-04-30 23:29:07 +02:00
Juergen Hoeller f6545cde38 Polishing 2013-04-30 23:29:06 +02:00
Juergen Hoeller 601c64a65c Removed broken applyQueryTimeout implementation (following a fix in 4.0) 2013-04-30 23:29:06 +02:00
Juergen Hoeller 964f1a6213 Refined HibernateJpaDialect for Hibernate 4.2 support
HibernateJpaDialect's HibernateConnectionHandle does not call close() for Hibernate 4.x anymore, since on 4.2, the exposed Connection handle isn't a "borrowed connection" wrapper but rather the actual underlying Connection - with a close() call immediately returning the Connection to the pool and making the local handle invalid for further use within the transaction.

Issue: SPR-10395
2013-04-30 23:29:05 +02:00
Juergen Hoeller 886cc2cce8 Fixed general test suite problems found during OpenJDK 8 upgrade
Issue: SPR-9639
(cherry picked from commit 19f783b)
2013-04-30 23:29:04 +02:00
Juergen Hoeller 5bdd2d245c Consistent Map/Set ordering
Use LinkedHashMaps/Sets wherever exposed to users, and code tests defensively in terms of expected Map/Set ordering. Otherwise, there'll be runtime order differences between JDK 7 and JDK 8 due to internal HashMap/Set implementation differences.

Issue: SPR-9639
(cherry picked from commit 9c09a0a)
2013-04-30 23:29:03 +02:00
Juergen Hoeller d0513f7521 Revised Joda-Time support (as a side effect of JSR-310 support in Spring 4.0)
Issue: SPR-9641
(cherry picked from commit b5d44e1)
2013-04-30 23:29:02 +02:00
Juergen Hoeller 265c0c1505 Minimized ASM usage
In particular, avoid accidental usage of ASM for core JDK types - which will fail in case of a new bytecode version in the JDK, even if the application itself has been compiled with an earlier bytecode target.

Issue: SPR-10292
(cherry picked from commit d3a4068)
2013-04-30 23:29:02 +02:00
Juergen Hoeller 886cf825cb Added "getName()" accessor to MethodReference
Issue: SPR-10422
(cherry picked from commit 5ff2653)
2013-04-30 23:29:01 +02:00
Juergen Hoeller 03033f6c06 Fixed typo in code example
Issue: SPR-10394
(cherry picked from commit f374b7a)
2013-04-30 23:29:00 +02:00
Juergen Hoeller 5ff2dfbe13 Removed references to deprecated queryForInt method from documentation
Issue: SPR-10257
(cherry picked from commit 6be954e)
2013-04-30 23:28:59 +02:00
Juergen Hoeller fa44ab6336 Removed unnecessary CGLIB 2.2 dependency from spring-test-mvc module
(cherry picked from commit 657bd80)
2013-04-30 23:28:58 +02:00
Juergen Hoeller eed1a58b81 Fixed annotation attribute processing for enum arrays
Based on https://github.com/SpringSource/spring-framework/pull/263
(cherry picked from commit 06fdfb0)
2013-04-30 23:28:57 +02:00
152 changed files with 2419 additions and 1772 deletions
+63 -36
View File
@@ -12,6 +12,11 @@ configure(allprojects) { project ->
group = "org.springframework"
version = qualifyVersionIfNecessary(version)
// The following is a work-around for allowing to build on JDK 8 until the
// Gradle build uses Ant 1.9.x by default. This is necessary to avoid the
// "Class not found: javac1.8" issue with Ant versions prior to 1.9.x
ant.properties["build.compiler"] = "javac1.7"
ext.aspectjVersion = "1.7.2"
ext.hsqldbVersion = "1.8.0.10"
ext.junitVersion = "4.11"
@@ -71,25 +76,26 @@ configure(allprojects) { project ->
}
ext.javadocLinks = [
"http://docs.oracle.com/javase/6/docs/api",
"http://docs.oracle.com/javaee/6/api",
"http://portals.apache.org/pluto/portlet-2.0-apidocs/",
"http://commons.apache.org/proper/commons-lang/javadocs/api-release/",
"http://commons.apache.org/proper/commons-codec/apidocs/",
"http://docs.oracle.com/javase/6/docs/api/",
"http://docs.oracle.com/javaee/6/api/",
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ
"http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
"http://glassfish.java.net/nonav/docs/v3/api/",
"http://docs.jboss.org/jbossas/javadoc/4.0.5/connector/",
"http://docs.jboss.org/jbossas/javadoc/7.1.2.Final/",
"http://aopalliance.sourceforge.net/doc/",
"http://glassfish.java.net/nonav/docs/v3/api/",
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // commonj
"http://quartz-scheduler.org/api/2.1.5/",
"http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
"http://hc.apache.org/httpclient-3.x/apidocs/",
"http://fasterxml.github.com/jackson-core/javadoc/2.0.0/",
"http://jackson.codehaus.org/1.4.2/javadoc/",
"http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
"http://ibatis.apache.org/docs/java/dev/",
"http://tiles.apache.org/framework/apidocs/",
"http://commons.apache.org/proper/commons-lang/javadocs/api-2.5/",
"http://commons.apache.org/proper/commons-codec/apidocs/",
"http://commons.apache.org/proper/commons-dbcp/apidocs/",
"http://portals.apache.org/pluto/portlet-2.0-apidocs/",
"http://tiles.apache.org/framework/apidocs/",
"http://ibatis.apache.org/docs/java/dev/",
"http://hc.apache.org/httpclient-3.x/apidocs/",
"http://aopalliance.sourceforge.net/doc/",
"http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
"http://ehcache.org/apidocs/",
"http://quartz-scheduler.org/api/2.1.5/",
"http://jackson.codehaus.org/1.4.2/javadoc/",
"http://fasterxml.github.com/jackson-core/javadoc/2.0.1/",
] as String[]
}
@@ -118,6 +124,9 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
options.author = true
options.header = project.name
options.links(project.ext.javadocLinks)
if(JavaVersion.current().isJava8Compatible()) {
options.addStringOption('Xdoclint:none', '-quiet')
}
// suppress warnings due to cross-module @see and @link references;
// note that global 'api' task does display all warnings.
@@ -245,6 +254,7 @@ project("spring-core") {
project("spring-beans") {
description = "Spring Beans"
dependencies {
compile(project(":spring-core"))
compile(files(project(":spring-core").cglibRepackJar))
@@ -256,6 +266,7 @@ project("spring-beans") {
project("spring-aop") {
description = "Spring AOP"
dependencies {
compile(project(":spring-core"))
compile(files(project(":spring-core").cglibRepackJar))
@@ -269,6 +280,7 @@ project("spring-aop") {
project("spring-expression") {
description = "Spring Expression Language (SpEL)"
dependencies {
compile(project(":spring-core"))
}
@@ -276,9 +288,11 @@ project("spring-expression") {
project("spring-instrument") {
description = "Spring Instrument"
dependencies {
compile(project(":spring-core"))
}
jar {
manifest.attributes["Premain-Class"] =
"org.springframework.instrument.InstrumentationSavingAgent"
@@ -287,6 +301,7 @@ project("spring-instrument") {
project("spring-instrument-tomcat") {
description = "Spring Instrument Tomcat"
dependencies {
provided("org.apache.tomcat:catalina:6.0.16")
}
@@ -294,6 +309,7 @@ project("spring-instrument-tomcat") {
project("spring-context") {
description = "Spring Context"
dependencies {
optional(project(":spring-instrument"))
compile(project(":spring-aop"))
@@ -306,12 +322,12 @@ project("spring-context") {
optional("javax.inject:javax.inject:1")
optional("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1")
optional("javax.persistence:persistence-api:1.0")
optional("javax.validation:validation-api:1.0.0.GA")
optional("org.beanshell:bsh:2.0b4")
optional("org.codehaus.groovy:groovy-all:1.8.8")
optional("org.jruby:jruby:1.6.5.1")
optional("joda-time:joda-time:2.1")
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.aspectj:aspectjweaver:${aspectjVersion}")
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
@@ -326,6 +342,7 @@ project("spring-context") {
project("spring-tx") {
description = "Spring Transaction"
dependencies {
optional(project(":spring-context")) // for JCA, @EnableTransactionManagement
optional(project(":spring-aop"))
@@ -355,10 +372,8 @@ project("spring-oxm") {
dependencies {
compile(project(":spring-beans"))
compile(project(":spring-core"))
optional(project(":spring-context")) // for Jaxb2Marshaller
compile("commons-lang:commons-lang:2.5")
testCompile(project(":spring-context"))
optional("com.thoughtworks.xstream:xstream:1.3.1")
optional("com.sun.xml.bind:jaxb-impl:2.1.7")
optional("org.jibx:jibx-run:1.2.3")
optional("org.apache.xmlbeans:xmlbeans:2.4.0")
optional("org.codehaus.castor:castor-xml:1.3.2")
@@ -373,6 +388,7 @@ project("spring-oxm") {
project("spring-jms") {
description = "Spring JMS"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-beans"))
@@ -391,6 +407,7 @@ project("spring-jms") {
project("spring-jdbc") {
description = "Spring JDBC"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-beans"))
@@ -407,6 +424,7 @@ project("spring-jdbc") {
project("spring-context-support") {
description = "Spring Context Support"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-beans"))
@@ -443,8 +461,6 @@ project("spring-web") {
compile(project(":spring-context"))
optional(project(":spring-oxm")) // for MarshallingHttpMessageConverter
compile("aopalliance:aopalliance:1.0")
optional("com.caucho:hessian:3.2.1")
optional("rome:rome:1.0")
optional("javax.el:el-api:1.0")
optional("javax.faces:jsf-api:1.2_08")
provided("javax.portlet:portlet-api:2.0")
@@ -453,6 +469,8 @@ project("spring-web") {
optional("javax.xml:jaxrpc-api:1.1")
provided("javax.xml.soap:saaj-api:1.3")
provided("javax.activation:activation:1.1")
optional("com.caucho:hessian:3.2.1")
optional("rome:rome:1.0")
optional("commons-fileupload:commons-fileupload:1.2")
optional("commons-io:commons-io:1.3")
optional("commons-httpclient:commons-httpclient:3.1")
@@ -487,16 +505,16 @@ project("spring-orm") {
dependencies {
compile("aopalliance:aopalliance:1.0")
optional("javax.persistence:persistence-api:1.0")
optional("org.eclipse.persistence:org.eclipse.persistence.core:1.0.1")
optional("org.eclipse.persistence:org.eclipse.persistence.jpa:1.0.1")
optional("org.hibernate:hibernate-core:3.3.2.GA")
optional("org.hibernate:hibernate-annotations:3.4.0.GA")
optional("org.hibernate:hibernate-entitymanager:3.4.0.GA")
optional("org.apache.openjpa:openjpa:1.1.0")
optional("org.eclipse.persistence:org.eclipse.persistence.core:1.0.1")
optional("org.eclipse.persistence:org.eclipse.persistence.jpa:1.0.1")
optional("toplink.essentials:toplink-essentials:2.0-41b")
optional("javax.jdo:jdo-api:3.0")
optional("org.apache.ibatis:ibatis-sqlmap:2.3.4.726")
optional("javax.persistence:persistence-api:1.0")
provided("javax.servlet:servlet-api:2.5")
testCompile("javax.servlet:javax.servlet-api:3.0.1")
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
@@ -517,11 +535,12 @@ project("spring-orm") {
project("spring-orm-hibernate4") {
description = "Spring Object/Relational Mapping - Hibernate 4 support"
merge.into = project(":spring-orm")
dependencies {
provided(project(":spring-tx"))
provided(project(":spring-jdbc"))
optional("org.hibernate:hibernate-core:4.1.0.Final")
optional("org.hibernate:hibernate-entitymanager:4.1.0.Final")
optional("org.hibernate:hibernate-core:4.1.9.Final")
optional("org.hibernate:hibernate-entitymanager:4.1.9.Final")
optional(project(":spring-web"))
optional("javax.servlet:servlet-api:2.5")
}
@@ -529,6 +548,7 @@ project("spring-orm-hibernate4") {
project("spring-webmvc") {
description = "Spring Web MVC"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-expression"))
@@ -541,7 +561,6 @@ project("spring-webmvc") {
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("velocity-tools:velocity-tools-view:1.4")
optional("net.sourceforge.jexcelapi:jxl:2.6.3")
optional("org.apache.poi:poi:3.0.2-FINAL")
optional("com.lowagie:itext:2.1.7")
@@ -550,6 +569,7 @@ project("spring-webmvc") {
}
optional("rome:rome:1.0")
optional("velocity:velocity:1.5")
optional("velocity-tools:velocity-tools-view:1.4")
optional("org.freemarker:freemarker:2.3.15")
optional("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
optional("com.fasterxml.jackson.core:jackson-databind:2.0.1")
@@ -588,6 +608,7 @@ project("spring-webmvc") {
project("spring-webmvc-tiles3") {
description = "Spring Framework Tiles3 Integration"
merge.into = project(":spring-webmvc")
dependencies {
provided(project(":spring-context"))
provided(project(":spring-web"))
@@ -618,6 +639,7 @@ project("spring-webmvc-tiles3") {
project("spring-webmvc-portlet") {
description = "Spring Web Portlet"
dependencies {
provided("javax.servlet:servlet-api:2.5")
provided("javax.portlet:portlet-api:2.0")
@@ -695,11 +717,9 @@ project("spring-test-mvc") {
testCompile(project(":spring-context-support"))
testCompile(project(":spring-oxm"))
testCompile("com.thoughtworks.xstream:xstream:1.3.1")
testCompile("cglib:cglib-nodep:2.2")
testCompile("rome:rome:1.0")
testCompile("javax.activation:activation:1.1")
testCompile("javax.mail:mail:1.4")
testCompile("javax.xml.bind:jaxb-api:2.2.6")
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") {
@@ -730,6 +750,7 @@ project("spring-struts") {
project("spring-aspects") {
description = "Spring Aspects"
apply from: "aspects.gradle"
dependencies {
optional(project(":spring-beans")) // for @Configurable support
optional(project(":spring-aop")) // for @Async support
@@ -747,6 +768,7 @@ project("spring-aspects") {
compile(project(":spring-beans")) // for "p" namespace visibility
testCompile(project(":spring-test"))
}
eclipse.project {
natures += "org.eclipse.ajdt.ui.ajnature"
buildCommands = [new org.gradle.plugins.ide.eclipse.model.
@@ -759,7 +781,7 @@ configure(rootProject) {
apply plugin: "docbook-reference"
apply plugin: "groovy"
apply plugin: "detect-split-packages"
// apply plugin: "detect-split-packages"
apply from: "${gradleScriptDir}/jdiff.gradle"
reference {
@@ -767,9 +789,11 @@ configure(rootProject) {
pdfFilename = "spring-framework-reference.pdf"
}
detectSplitPackages {
projectsToScan -= project(":spring-instrument-tomcat")
}
// TODO: DetectSplitPackagesPlugin fails in line 154 due to method not found on java.io.File.
// TODO: Possibly related to user rights or OS differences on OpenJDK 8; works fine on JDK 7.
// detectSplitPackages {
// projectsToScan -= project(":spring-instrument-tomcat")
// }
// don't publish the default jar for the root project
configurations.archives.artifacts.clear()
@@ -786,7 +810,7 @@ configure(rootProject) {
testCompile(project(":spring-web"))
testCompile(project(":spring-webmvc-portlet"))
testCompile(project(":spring-orm"))
testCompile("org.hibernate:hibernate-core:4.1.0.Final")
testCompile("org.hibernate:hibernate-core:4.1.9.Final")
testCompile("javax.servlet:servlet-api:2.5")
testCompile("javax.portlet:portlet-api:2.0")
testCompile("javax.inject:javax.inject:1")
@@ -812,6 +836,9 @@ configure(rootProject) {
options.stylesheetFile = file("src/api/stylesheet.css")
options.splitIndex = true
options.links(project.ext.javadocLinks)
if(JavaVersion.current().isJava8Compatible()) {
options.addStringOption('Xdoclint:none', '-quiet')
}
source subprojects.collect { project ->
project.sourceSets.main.allJava
@@ -822,7 +849,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" },
+1 -1
View File
@@ -1 +1 @@
version=3.2.3.BUILD-SNAPSHOT
version=3.2.3.RELEASE
@@ -45,43 +45,41 @@ public class AspectJWeaverMessageHandler implements IMessageHandler {
private static final String AJ_ID = "[AspectJ] ";
private static final Log LOGGER = LogFactory.getLog("AspectJ Weaver");
private static final Log logger = LogFactory.getLog("AspectJ Weaver");
public boolean handleMessage(IMessage message) throws AbortException {
Kind messageKind = message.getKind();
if (messageKind == IMessage.DEBUG) {
if (LOGGER.isDebugEnabled() || LOGGER.isTraceEnabled()) {
LOGGER.debug(makeMessageFor(message));
if (logger.isDebugEnabled()) {
logger.debug(makeMessageFor(message));
return true;
}
}
else if ((messageKind == IMessage.INFO) || (messageKind == IMessage.WEAVEINFO)) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(makeMessageFor(message));
else if (messageKind == IMessage.INFO || messageKind == IMessage.WEAVEINFO) {
if (logger.isInfoEnabled()) {
logger.info(makeMessageFor(message));
return true;
}
}
else if (messageKind == IMessage.WARNING) {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn(makeMessageFor(message));
if (logger.isWarnEnabled()) {
logger.warn(makeMessageFor(message));
return true;
}
}
else if (messageKind == IMessage.ERROR) {
if (LOGGER.isErrorEnabled()) {
LOGGER.error(makeMessageFor(message));
if (logger.isErrorEnabled()) {
logger.error(makeMessageFor(message));
return true;
}
}
else if (messageKind == IMessage.ABORT) {
if (LOGGER.isFatalEnabled()) {
LOGGER.fatal(makeMessageFor(message));
if (logger.isFatalEnabled()) {
logger.fatal(makeMessageFor(message));
return true;
}
}
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.
@@ -19,6 +19,7 @@ package org.springframework.aop.aspectj.annotation;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.util.ClassUtils;
@@ -105,7 +106,7 @@ public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInst
if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) {
return ((Ordered) this.beanFactory.getBean(this.name)).getOrder();
}
Order order = type.getAnnotation(Order.class);
Order order = AnnotationUtils.findAnnotation(type, Order.class);
if (order != null) {
return order.value();
}
@@ -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,7 @@ package org.springframework.aop.aspectj.annotation;
import org.springframework.aop.aspectj.SimpleAspectInstanceFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
/**
@@ -58,7 +59,7 @@ public class SimpleMetadataAwareAspectInstanceFactory extends SimpleAspectInstan
*/
@Override
protected int getOrderForAspectClass(Class<?> aspectClass) {
Order order = aspectClass.getAnnotation(Order.class);
Order order = AnnotationUtils.findAnnotation(aspectClass, Order.class);
if (order != null) {
return order.value();
}
@@ -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,7 @@ package org.springframework.aop.aspectj.annotation;
import org.springframework.aop.aspectj.SingletonAspectInstanceFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
/**
@@ -59,7 +60,7 @@ public class SingletonMetadataAwareAspectInstanceFactory extends SingletonAspect
*/
@Override
protected int getOrderForAspectClass(Class<?> aspectClass) {
Order order = aspectClass.getAnnotation(Order.class);
Order order = AnnotationUtils.findAnnotation(aspectClass, Order.class);
if (order != null) {
return order.value();
}
@@ -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.
@@ -58,15 +58,19 @@ public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implem
* allowing for ASM-based processing and avoidance of early loading of the bean class.
* Note that this constructor is functionally equivalent to
* {@link org.springframework.context.annotation.ScannedGenericBeanDefinition
* ScannedGenericBeanDefinition}, however the semantics of the latter indicate that
* a bean was discovered specifically via component-scanning as opposed to other
* means.
* ScannedGenericBeanDefinition}, however the semantics of the latter indicate that a
* bean was discovered specifically via component-scanning as opposed to other means.
* @param metadata the annotation metadata for the bean class in question
* @since 3.1.1
*/
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
Assert.notNull(metadata, "AnnotationMetadata must not be null");
setBeanClassName(metadata.getClassName());
if (metadata instanceof StandardAnnotationMetadata) {
setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
}
else {
setBeanClassName(metadata.getClassName());
}
this.metadata = metadata;
}
@@ -185,7 +185,7 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
* @see #AUTOWIRE_BY_TYPE
* @see #AUTOWIRE_CONSTRUCTOR
*/
Object createBean(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
/**
* Instantiate a new bean instance of the given class with the specified autowire
@@ -213,7 +213,7 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
* @see #applyBeanPostProcessorsBeforeInitialization
* @see #applyBeanPostProcessorsAfterInitialization
*/
Object autowire(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
/**
* Autowire the bean properties of the given bean instance by name or type.
@@ -171,6 +171,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
setParentBeanFactory(parentBeanFactory);
}
/**
* Set the instantiation strategy to use for creating bean instances.
* Default is CglibSubclassingInstantiationStrategy.
@@ -243,7 +244,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* Ignore the given dependency type for autowiring:
* for example, String. Default is none.
*/
public void ignoreDependencyType(Class type) {
public void ignoreDependencyType(Class<?> type) {
this.ignoredDependencyTypes.add(type);
}
@@ -257,11 +258,10 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.context.ApplicationContextAware
*/
public void ignoreDependencyInterface(Class ifc) {
public void ignoreDependencyInterface(Class<?> ifc) {
this.ignoredDependencyInterfaces.add(ifc);
}
@Override
public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
super.copyConfigurationFrom(otherFactory);
@@ -305,12 +305,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
RootBeanDefinition bd = null;
if (mbd instanceof RootBeanDefinition) {
RootBeanDefinition rbd = (RootBeanDefinition) mbd;
if (rbd.isPrototype()) {
bd = rbd;
}
bd = (rbd.isPrototype() ? rbd : rbd.cloneBeanDefinition());
}
if (bd == null) {
bd = new RootBeanDefinition(mbd);
if (!mbd.isPrototype()) {
if (bd == null) {
bd = new RootBeanDefinition(mbd);
}
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bd.allowCaching = false;
}
@@ -329,14 +329,14 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
// Specialized methods for fine-grained control over the bean lifecycle
//-------------------------------------------------------------------------
public Object createBean(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
public Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
return createBean(beanClass.getName(), bd, null);
}
public Object autowire(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
public Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
final RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
@@ -346,10 +346,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
else {
Object bean;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
bean = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return getInstantiationStrategy().instantiate(bd, null, parent);
}
@@ -358,7 +356,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
else {
bean = getInstantiationStrategy().instantiate(bd, null, parent);
}
populateBean(beanClass.getName(), bd, new BeanWrapperImpl(bean));
return bean;
}
@@ -490,7 +487,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
@@ -587,7 +584,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
Class predicted = ibp.predictBeanType(targetType, beanName);
Class<?> predicted = ibp.predictBeanType(targetType, beanName);
if (predicted != null && (typesToMatch.length != 1 || !FactoryBean.class.equals(typesToMatch[0]) ||
FactoryBean.class.isAssignableFrom(predicted))) {
return predicted;
@@ -688,22 +685,19 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
// Try to obtain the FactoryBean's object type without instantiating it at all.
BeanDefinition fbDef = getBeanDefinition(factoryBeanName);
if (fbDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) fbDef).hasBeanClass()) {
Class<?> fbClass = ((AbstractBeanDefinition) fbDef).getBeanClass();
if (ClassUtils.isCglibProxyClass(fbClass)) {
// CGLIB subclass methods hide generic parameters. look at the superclass.
fbClass = fbClass.getSuperclass();
}
// CGLIB subclass methods hide generic parameters; look at the original user class.
Class<?> fbClass = ClassUtils.getUserClass(((AbstractBeanDefinition) fbDef).getBeanClass());
// Find the given factory method, taking into account that in the case of
// @Bean methods, there may be parameters present.
ReflectionUtils.doWithMethods(fbClass,
new ReflectionUtils.MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
if (method.getName().equals(factoryMethodName) &&
FactoryBean.class.isAssignableFrom(method.getReturnType())) {
objectType.value = GenericTypeResolver.resolveReturnTypeArgument(method, FactoryBean.class);
new ReflectionUtils.MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
if (method.getName().equals(factoryMethodName) &&
FactoryBean.class.isAssignableFrom(method.getReturnType())) {
objectType.value = GenericTypeResolver.resolveReturnTypeArgument(method, FactoryBean.class);
}
}
}
});
});
if (objectType.value != null) {
return objectType.value;
}
@@ -836,7 +830,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @throws BeansException if any post-processing failed
* @see MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
*/
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class beanType, String beanName)
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName)
throws BeansException {
try {
@@ -887,7 +881,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @throws BeansException if any post-processing failed
* @see InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
*/
protected Object applyBeanPostProcessorsBeforeInstantiation(Class beanClass, String beanName)
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName)
throws BeansException {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
@@ -916,7 +910,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
*/
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// Make sure bean class is actually resolved at this point.
Class beanClass = resolveBeanClass(mbd, beanName);
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
@@ -968,7 +962,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
*/
protected Constructor[] determineConstructorsFromBeanPostProcessors(Class beanClass, String beanName)
protected Constructor[] determineConstructorsFromBeanPostProcessors(Class<?> beanClass, String beanName)
throws BeansException {
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
@@ -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.
@@ -54,7 +54,7 @@ public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable
private ClassLoader beanClassLoader;
private Environment environment = new StandardEnvironment();
private Environment environment;
private BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator();
@@ -90,7 +90,7 @@ public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable
// Inherit Environment if possible
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable)this.registry).getEnvironment();
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
this.environment = new StandardEnvironment();
@@ -511,26 +511,32 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
}
}
Class<?> beanClass = predictBeanType(beanName, mbd, typesToMatch);
if (beanClass == null) {
Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch);
if (beanType == null) {
return false;
}
// Check bean class whether we're dealing with a FactoryBean.
if (FactoryBean.class.isAssignableFrom(beanClass)) {
if (FactoryBean.class.isAssignableFrom(beanType)) {
if (!BeanFactoryUtils.isFactoryDereference(name)) {
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
Class<?> type = getTypeForFactoryBean(beanName, mbd);
return (type != null && typeToMatch.isAssignableFrom(type));
}
else {
return typeToMatch.isAssignableFrom(beanClass);
beanType = getTypeForFactoryBean(beanName, mbd);
if (beanType == null) {
return false;
}
}
}
else {
return !BeanFactoryUtils.isFactoryDereference(name) &&
typeToMatch.isAssignableFrom(beanClass);
else if (BeanFactoryUtils.isFactoryDereference(name)) {
// Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
// type but we nevertheless are being asked to dereference a FactoryBean...
// Let's check the original bean class and proceed with it if it is a FactoryBean.
beanType = predictBeanType(beanName, mbd, FactoryBean.class);
if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) {
return false;
}
}
return typeToMatch.isAssignableFrom(beanType);
}
}
@@ -1335,8 +1341,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
* @param mbd the corresponding bean definition
*/
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
Class<?> beanClass = predictBeanType(beanName, mbd, FactoryBean.class);
return (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass));
Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);
return (beanType != null && FactoryBean.class.isAssignableFrom(beanType));
}
/**
@@ -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.
@@ -17,7 +17,6 @@
package org.springframework.beans.factory.support;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.util.ObjectUtils;
@@ -98,7 +97,7 @@ public class ChildBeanDefinition extends AbstractBeanDefinition {
* @param pvs the property values to apply
*/
public ChildBeanDefinition(
String parentName, Class beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
String parentName, Class<?> beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
super(cargs, pvs);
this.parentName = parentName;
@@ -128,7 +127,7 @@ public class ChildBeanDefinition extends AbstractBeanDefinition {
* @param original the original bean definition to copy from
*/
public ChildBeanDefinition(ChildBeanDefinition original) {
super((BeanDefinition) original);
super(original);
}
@@ -107,7 +107,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
* Create a new RootBeanDefinition for a singleton.
* @param beanClass the class of the bean to instantiate
*/
public RootBeanDefinition(Class beanClass) {
public RootBeanDefinition(Class<?> beanClass) {
super();
setBeanClass(beanClass);
}
@@ -147,7 +147,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
* @param dependencyCheck whether to perform a dependency check for objects
* (not applicable to autowiring a constructor, thus ignored there)
*/
public RootBeanDefinition(Class beanClass, int autowireMode, boolean dependencyCheck) {
public RootBeanDefinition(Class<?> beanClass, int autowireMode, boolean dependencyCheck) {
super();
setBeanClass(beanClass);
setAutowireMode(autowireMode);
@@ -191,7 +191,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
* @param cargs the constructor argument values to apply
* @param pvs the property values to apply
*/
public RootBeanDefinition(Class beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
public RootBeanDefinition(Class<?> beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
super(cargs, pvs);
setBeanClass(beanClass);
}
@@ -225,7 +225,11 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
* @param original the original bean definition to copy from
*/
public RootBeanDefinition(RootBeanDefinition original) {
this((BeanDefinition) original);
super(original);
this.decoratedDefinition = original.decoratedDefinition;
this.allowCaching = original.allowCaching;
this.targetType = original.targetType;
this.isFactoryMethodUnique = original.isFactoryMethodUnique;
}
/**
@@ -235,13 +239,6 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
*/
RootBeanDefinition(BeanDefinition original) {
super(original);
if (original instanceof RootBeanDefinition) {
RootBeanDefinition originalRbd = (RootBeanDefinition) original;
this.decoratedDefinition = originalRbd.decoratedDefinition;
this.allowCaching = originalRbd.allowCaching;
this.targetType = originalRbd.targetType;
this.isFactoryMethodUnique = originalRbd.isFactoryMethodUnique;
}
}
@@ -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.
@@ -78,9 +78,12 @@ public class ResourceEditorRegistrar implements PropertyEditorRegistrar {
}
/**
* Create a new ResourceEditorRegistrar for the given ResourceLoader
* Create a new ResourceEditorRegistrar for the given {@link ResourceLoader}
* and {@link PropertyResolver}.
* @param resourceLoader the ResourceLoader (or ResourcePatternResolver)
* to create editors for (usually an ApplicationContext)
* @param propertyResolver the PropertyResolver (usually an Environment)
* @see org.springframework.core.env.Environment
* @see org.springframework.core.io.support.ResourcePatternResolver
* @see org.springframework.context.ApplicationContext
*/
@@ -712,6 +712,20 @@ public class DefaultListableBeanFactoryTests {
factory.getMergedBeanDefinition("child"), factory.getMergedBeanDefinition("child"));
}
@Test
public void testGetTypeWorksAfterParentChildMerging() {
RootBeanDefinition parentDefinition = new RootBeanDefinition(TestBean.class);
ChildBeanDefinition childDefinition = new ChildBeanDefinition("parent", DerivedTestBean.class, null, null);
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition("parent", parentDefinition);
factory.registerBeanDefinition("child", childDefinition);
factory.freezeConfiguration();
assertEquals(TestBean.class, factory.getType("parent"));
assertEquals(DerivedTestBean.class, factory.getType("child"));
}
@Test
public void testNameAlreadyBound() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
@@ -16,59 +16,59 @@
package org.springframework.beans.factory.support;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
/**
* Unit tests for SPR-8954, in which a custom {@link InstantiationAwareBeanPostProcessor}
* forces the predicted type of a FactoryBean, effectively preventing retrieval of the
* bean from calls to #getBeansOfType(FactoryBean.class). The implementation of
* {@link AbstractBeanFactory#isFactoryBean(String, RootBeanDefinition)} now ensures
* that not only the predicted bean type is considered, but also the original bean
* definition's beanClass.
* {@link AbstractBeanFactory#isFactoryBean(String, RootBeanDefinition)} now ensures that
* not only the predicted bean type is considered, but also the original bean definition's
* beanClass.
*
* @author Chris Beams
* @author Oliver Gierke
*/
public class Spr8954Tests {
@Test
public void repro() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
private DefaultListableBeanFactory bf;
@Before
public void setUp() {
bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("foo", new RootBeanDefinition(FooFactoryBean.class));
bf.addBeanPostProcessor(new PredictingBPP());
}
@Test
public void repro() {
assertThat(bf.getBean("foo"), instanceOf(Foo.class));
assertThat(bf.getBean("&foo"), instanceOf(FooFactoryBean.class));
assertThat(bf.isTypeMatch("&foo", FactoryBean.class), is(true));
@SuppressWarnings("rawtypes")
Map<String, FactoryBean> fbBeans = bf.getBeansOfType(FactoryBean.class);
assertThat(1, equalTo(fbBeans.size()));
assertThat("&foo", equalTo(fbBeans.keySet().iterator().next()));
assertThat(fbBeans.size(), is(1));
assertThat(fbBeans.keySet(), hasItem("&foo"));
Map<String, AnInterface> aiBeans = bf.getBeansOfType(AnInterface.class);
assertThat(1, equalTo(aiBeans.size()));
assertThat("&foo", equalTo(aiBeans.keySet().iterator().next()));
assertThat(aiBeans.size(), is(1));
assertThat(aiBeans.keySet(), hasItem("&foo"));
}
@Test
public void findsBeansByTypeIfNotInstantiated() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("foo", new RootBeanDefinition(FooFactoryBean.class));
bf.addBeanPostProcessor(new PredictingBPP());
assertThat(bf.isTypeMatch("&foo", FactoryBean.class), is(true));
@SuppressWarnings("rawtypes")
@@ -77,8 +77,21 @@ public class Spr8954Tests {
assertThat("&foo", equalTo(fbBeans.keySet().iterator().next()));
Map<String, AnInterface> aiBeans = bf.getBeansOfType(AnInterface.class);
assertThat(1, equalTo(aiBeans.size()));
assertThat("&foo", equalTo(aiBeans.keySet().iterator().next()));
assertThat(aiBeans.size(), is(1));
assertThat(aiBeans.keySet(), hasItem("&foo"));
}
/**
* SPR-10517
*/
@Test
public void findsFactoryBeanNameByTypeWithoutInstantiation() {
String[] names = bf.getBeanNamesForType(AnInterface.class, false, false);
assertThat(Arrays.asList(names), hasItem("&foo"));
Map<String, AnInterface> beans = bf.getBeansOfType(AnInterface.class, false, false);
assertThat(beans.size(), is(1));
assertThat(beans.keySet(), hasItem("&foo"));
}
@@ -116,8 +129,7 @@ public class Spr8954Tests {
@Override
public Class<?> predictBeanType(Class<?> beanClass, String beanName) {
return FactoryBean.class.isAssignableFrom(beanClass) ?
PredictedType.class : null;
return FactoryBean.class.isAssignableFrom(beanClass) ? PredictedType.class : null;
}
}
@@ -29,7 +29,7 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.util.ObjectUtils;
/**
* @author Rick Evans
@@ -38,13 +38,13 @@ import org.springframework.tests.sample.beans.TestBean;
public class XmlBeanDefinitionReaderTests extends TestCase {
public void testSetParserClassSunnyDay() {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
new XmlBeanDefinitionReader(registry).setDocumentReaderClass(DefaultBeanDefinitionDocumentReader.class);
}
public void testSetParserClassToNull() {
try {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
new XmlBeanDefinitionReader(registry).setDocumentReaderClass(null);
fail("Should have thrown IllegalArgumentException (null parserClass)");
}
@@ -54,7 +54,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
public void testSetParserClassToUnsupportedParserType() throws Exception {
try {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
new XmlBeanDefinitionReader(registry).setDocumentReaderClass(String.class);
fail("Should have thrown IllegalArgumentException (unsupported parserClass)");
}
@@ -64,7 +64,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
public void testWithOpenInputStream() {
try {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
Resource resource = new InputStreamResource(getClass().getResourceAsStream("test.xml"));
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
fail("Should have thrown BeanDefinitionStoreException (can't determine validation mode)");
@@ -74,7 +74,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
}
public void testWithOpenInputStreamAndExplicitValidationMode() {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
Resource resource = new InputStreamResource(getClass().getResourceAsStream("test.xml"));
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_DTD);
@@ -83,14 +83,14 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
}
public void testWithImport() {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
Resource resource = new ClassPathResource("import.xml", getClass());
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
testBeanDefinitions(registry);
}
public void testWithWildcardImport() {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
Resource resource = new ClassPathResource("importPattern.xml", getClass());
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
testBeanDefinitions(registry);
@@ -98,7 +98,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
public void testWithInputSource() {
try {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
InputSource resource = new InputSource(getClass().getResourceAsStream("test.xml"));
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
fail("Should have thrown BeanDefinitionStoreException (can't determine validation mode)");
@@ -108,7 +108,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
}
public void testWithInputSourceAndExplicitValidationMode() {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
InputSource resource = new InputSource(getClass().getResourceAsStream("test.xml"));
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_DTD);
@@ -117,7 +117,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
}
public void testWithFreshInputStream() {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
Resource resource = new ClassPathResource("test.xml", getClass());
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
testBeanDefinitions(registry);
@@ -133,9 +133,10 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
assertEquals(TestBean.class.getName(), registry.getBeanDefinition("rod").getBeanClassName());
assertEquals(TestBean.class.getName(), registry.getBeanDefinition("aliased").getBeanClassName());
assertTrue(registry.isAlias("youralias"));
assertEquals(2, registry.getAliases("aliased").length);
assertEquals("myalias", registry.getAliases("aliased")[0]);
assertEquals("youralias", registry.getAliases("aliased")[1]);
String[] aliases = registry.getAliases("aliased");
assertEquals(2, aliases.length);
assertTrue(ObjectUtils.containsElement(aliases, "myalias"));
assertTrue(ObjectUtils.containsElement(aliases, "youralias"));
}
public void testDtdValidationAutodetect() throws Exception {
@@ -147,7 +148,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
}
private void doTestValidation(String resourceName) throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();;
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
Resource resource = new ClassPathResource(resourceName, getClass());
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(resource);
TestBean bean = (TestBean) factory.getBean("testBean");
@@ -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.
@@ -90,7 +90,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
/**
* Create a ClassPathScanningCandidateComponentProvider.
* Create a ClassPathScanningCandidateComponentProvider with a {@link StandardEnvironment}.
* @param useDefaultFilters whether to register the default filters for the
* {@link Component @Component}, {@link Repository @Repository},
* {@link Service @Service}, and {@link Controller @Controller}
@@ -101,6 +101,15 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
this(useDefaultFilters, new StandardEnvironment());
}
/**
* Create a ClassPathScanningCandidateComponentProvider with the given {@link Environment}.
* @param useDefaultFilters whether to register the default filters for the
* {@link Component @Component}, {@link Repository @Repository},
* {@link Service @Service}, and {@link Controller @Controller}
* stereotype annotations
* @param environment the Environment to use
* @see #registerDefaultFilters()
*/
public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) {
if (useDefaultFilters) {
registerDefaultFilters();
@@ -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.
@@ -36,8 +36,8 @@ import org.springframework.util.ClassUtils;
/**
* Represents a user-defined {@link Configuration @Configuration} class.
* Includes a set of {@link Bean} methods, including all such methods defined in the
* ancestry of the class, in a 'flattened-out' manner.
* Includes a set of {@link Bean} methods, including all such methods
* defined in the ancestry of the class, in a 'flattened-out' manner.
*
* @author Chris Beams
* @author Juergen Hoeller
@@ -51,15 +51,15 @@ final class ConfigurationClass {
private final Resource resource;
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
new LinkedHashMap<String, Class<? extends BeanDefinitionReader>>();
private final Set<BeanMethod> beanMethods = new LinkedHashSet<BeanMethod>();
private String beanName;
private final boolean imported;
private final Set<BeanMethod> beanMethods = new LinkedHashSet<BeanMethod>();
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
new LinkedHashMap<String, Class<? extends BeanDefinitionReader>>();
/**
* Create a new {@link ConfigurationClass} with the given name.
@@ -81,7 +81,7 @@ final class ConfigurationClass {
* using the {@link Import} annotation or automatically processed as a nested
* configuration class (if imported is {@code true}).
* @param metadataReader reader used to parse the underlying {@link Class}
* @param beanName name of the {@code @Configuration} class bean
* @param imported whether the given configuration class is being imported
* @since 3.1.1
*/
public ConfigurationClass(MetadataReader metadataReader, boolean imported) {
@@ -98,7 +98,7 @@ final class ConfigurationClass {
* @see ConfigurationClass#ConfigurationClass(Class, boolean)
*/
public ConfigurationClass(Class<?> clazz, String beanName) {
Assert.hasText(beanName, "bean name must not be null");
Assert.hasText(beanName, "Bean name must not be null");
this.metadata = new StandardAnnotationMetadata(clazz, true);
this.resource = new DescriptiveResource(clazz.toString());
this.beanName = beanName;
@@ -110,7 +110,7 @@ final class ConfigurationClass {
* using the {@link Import} annotation or automatically processed as a nested
* configuration class (if imported is {@code true}).
* @param clazz the underlying {@link Class} to represent
* @param beanName name of the {@code @Configuration} class bean
* @param imported whether the given configuration class is being imported
* @since 3.1.1
*/
public ConfigurationClass(Class<?> clazz, boolean imported) {
@@ -119,6 +119,7 @@ final class ConfigurationClass {
this.imported = imported;
}
public AnnotationMetadata getMetadata() {
return this.metadata;
}
@@ -131,6 +132,14 @@ final class ConfigurationClass {
return ClassUtils.getShortName(getMetadata().getClassName());
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public String getBeanName() {
return this.beanName;
}
/**
* Return whether this configuration class was registered via @{@link Import} or
* automatically registered due to being nested within another configuration class.
@@ -140,14 +149,6 @@ final class ConfigurationClass {
return this.imported;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public String getBeanName() {
return this.beanName;
}
public void addBeanMethod(BeanMethod method) {
this.beanMethods.add(method);
}
@@ -156,8 +157,7 @@ final class ConfigurationClass {
return this.beanMethods;
}
public void addImportedResource(
String importedResource, Class<? extends BeanDefinitionReader> readerClass) {
public void addImportedResource(String importedResource, Class<? extends BeanDefinitionReader> readerClass) {
this.importedResources.put(importedResource, readerClass);
}
@@ -165,28 +165,8 @@ final class ConfigurationClass {
return this.importedResources;
}
public void validate(ProblemReporter problemReporter) {
// An @Bean method may only be overloaded through inheritance. No single
// @Configuration class may declare two @Bean methods with the same name.
final char hashDelim = '#';
Map<String, Integer> methodNameCounts = new HashMap<String, Integer>();
for (BeanMethod beanMethod : beanMethods) {
String dClassName = beanMethod.getMetadata().getDeclaringClassName();
String methodName = beanMethod.getMetadata().getMethodName();
String fqMethodName = dClassName + hashDelim + methodName;
Integer currentCount = methodNameCounts.get(fqMethodName);
int newCount = currentCount != null ? currentCount + 1 : 1;
methodNameCounts.put(fqMethodName, newCount);
}
for (String methodName : methodNameCounts.keySet()) {
int count = methodNameCounts.get(methodName);
if (count > 1) {
String shortMethodName = methodName.substring(methodName.indexOf(hashDelim)+1);
problemReporter.error(new BeanMethodOverloadingProblem(shortMethodName, count));
}
}
// A configuration class may not be final (CGLIB limitation)
if (getMetadata().isAnnotated(Configuration.class.getName())) {
if (getMetadata().isFinal()) {
@@ -194,6 +174,23 @@ final class ConfigurationClass {
}
}
// An @Bean method may only be overloaded through inheritance. No single
// @Configuration class may declare two @Bean methods with the same name.
Map<String, Integer> methodNameCounts = new HashMap<String, Integer>();
for (BeanMethod beanMethod : this.beanMethods) {
String fqMethodName = beanMethod.getFullyQualifiedMethodName();
Integer currentCount = methodNameCounts.get(fqMethodName);
int newCount = currentCount != null ? currentCount + 1 : 1;
methodNameCounts.put(fqMethodName, newCount);
}
for (String fqMethodName : methodNameCounts.keySet()) {
int count = methodNameCounts.get(fqMethodName);
if (count > 1) {
String shortMethodName = ConfigurationMethod.getShortMethodName(fqMethodName);
problemReporter.error(new BeanMethodOverloadingProblem(shortMethodName, count));
}
}
for (BeanMethod beanMethod : this.beanMethods) {
beanMethod.validate(problemReporter);
}
@@ -134,8 +134,6 @@ class ConfigurationClassBeanDefinitionReader {
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
AnnotationMetadata metadata = configClass.getMetadata();
BeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
String className = metadata.getClassName();
configBeanDef.setBeanClassName(className);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) {
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
this.registry.registerBeanDefinition(configBeanName, configBeanDef);
@@ -146,7 +144,7 @@ class ConfigurationClassBeanDefinitionReader {
}
else {
this.problemReporter.error(
new InvalidConfigurationImportProblem(className, configClass.getResource(), metadata));
new InvalidConfigurationImportProblem(metadata.getClassName(), configClass.getResource(), metadata));
}
}
@@ -17,11 +17,12 @@
package org.springframework.context.annotation;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -42,6 +43,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.NestedIOException;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.Environment;
@@ -54,7 +56,7 @@ import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import static org.springframework.context.annotation.MetadataUtils.*;
@@ -83,16 +85,6 @@ class ConfigurationClassParser {
private final ProblemReporter problemReporter;
private final ImportStack importStack = new ImportStack();
private final Set<String> knownSuperclasses = new LinkedHashSet<String>();
private final Set<ConfigurationClass> configurationClasses =
new LinkedHashSet<ConfigurationClass>();
private final Stack<PropertySource<?>> propertySources =
new Stack<PropertySource<?>>();
private final Environment environment;
private final ResourceLoader resourceLoader;
@@ -101,6 +93,14 @@ class ConfigurationClassParser {
private final ComponentScanAnnotationParser componentScanParser;
private final Set<ConfigurationClass> configurationClasses = new LinkedHashSet<ConfigurationClass>();
private final Map<String, ConfigurationClass> knownSuperclasses = new HashMap<String, ConfigurationClass>();
private final Stack<PropertySource<?>> propertySources = new Stack<PropertySource<?>>();
private final ImportStack importStack = new ImportStack();
/**
* Create a new {@link ConfigurationClassParser} instance that will be used
@@ -149,70 +149,42 @@ class ConfigurationClassParser {
}
}
// recursively process the configuration class and its superclass hierarchy
if (this.configurationClasses.contains(configClass) && configClass.getBeanName() != null) {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext();) {
if (configClass.equals(it.next())) {
it.remove();
}
}
}
// Recursively process the configuration class and its superclass hierarchy.
do {
metadata = doProcessConfigurationClass(configClass, metadata);
}
while (metadata != null);
if (this.configurationClasses.contains(configClass) && configClass.getBeanName() != null) {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
}
this.configurationClasses.add(configClass);
}
/**
* @return annotation metadata of superclass, null if none found or previously processed
* @return annotation metadata of superclass, {@code null} if none found or previously processed
*/
protected AnnotationMetadata doProcessConfigurationClass(
ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
// recursively process any member (nested) classes first
for (String memberClassName : metadata.getMemberClassNames()) {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(memberClassName);
AnnotationMetadata memberClassMetadata = reader.getAnnotationMetadata();
if (ConfigurationClassUtils.isConfigurationCandidate(memberClassMetadata)) {
processConfigurationClass(new ConfigurationClass(reader, true));
}
}
processMemberClasses(metadata);
// process any @PropertySource annotations
AnnotationAttributes propertySource =
attributesFor(metadata, org.springframework.context.annotation.PropertySource.class);
AnnotationAttributes propertySource = attributesFor(metadata, org.springframework.context.annotation.PropertySource.class);
if (propertySource != null) {
String name = propertySource.getString("name");
String[] locations = propertySource.getStringArray("value");
int nLocations = locations.length;
if (nLocations == 0) {
throw new IllegalArgumentException("At least one @PropertySource(value) location is required");
}
for (int i = 0; i < nLocations; i++) {
locations[i] = this.environment.resolveRequiredPlaceholders(locations[i]);
}
ClassLoader classLoader = this.resourceLoader.getClassLoader();
if (!StringUtils.hasText(name)) {
for (String location : locations) {
this.propertySources.push(new ResourcePropertySource(location, classLoader));
}
}
else {
if (nLocations == 1) {
this.propertySources.push(new ResourcePropertySource(name, locations[0], classLoader));
}
else {
CompositePropertySource ps = new CompositePropertySource(name);
for (String location : locations) {
ps.addPropertySource(new ResourcePropertySource(location, classLoader));
}
this.propertySources.push(ps);
}
}
processPropertySource(propertySource);
}
// process any @ComponentScan annotions
// process any @ComponentScan annotations
AnnotationAttributes componentScan = attributesFor(metadata, ComponentScan.class);
if (componentScan != null) {
// the config class is annotated with @ComponentScan -> perform the scan immediately
@@ -228,9 +200,11 @@ class ConfigurationClassParser {
}
// process any @Import annotations
Set<String> imports = getImports(metadata.getClassName(), null, new HashSet<String>());
if (!CollectionUtils.isEmpty(imports)) {
processImport(configClass, imports.toArray(new String[imports.size()]), true);
Set<Object> imports = new LinkedHashSet<Object>();
Set<Object> visited = new LinkedHashSet<Object>();
collectImports(metadata, imports, visited);
if (!imports.isEmpty()) {
processImport(configClass, imports, true);
}
// process any @ImportResource annotations
@@ -252,7 +226,8 @@ class ConfigurationClassParser {
// process superclass, if any
if (metadata.hasSuperClass()) {
String superclass = metadata.getSuperClassName();
if (this.knownSuperclasses.add(superclass)) {
if (!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// superclass found, return its annotation metadata and recurse
if (metadata instanceof StandardAnnotationMetadata) {
Class<?> clazz = ((StandardAnnotationMetadata) metadata).getIntrospectedClass();
@@ -279,6 +254,65 @@ class ConfigurationClassParser {
return null;
}
/**
* Register member (nested) classes that happen to be configuration classes themselves.
* @param metadata the metadata representation of the containing class
* @throws IOException if there is any problem reading metadata from a member class
*/
private void processMemberClasses(AnnotationMetadata metadata) throws IOException {
if (metadata instanceof StandardAnnotationMetadata) {
for (Class<?> memberClass : ((StandardAnnotationMetadata) metadata).getIntrospectedClass().getDeclaredClasses()) {
if (ConfigurationClassUtils.isConfigurationCandidate(new StandardAnnotationMetadata(memberClass))) {
processConfigurationClass(new ConfigurationClass(memberClass, true));
}
}
}
else {
for (String memberClassName : metadata.getMemberClassNames()) {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(memberClassName);
AnnotationMetadata memberClassMetadata = reader.getAnnotationMetadata();
if (ConfigurationClassUtils.isConfigurationCandidate(memberClassMetadata)) {
processConfigurationClass(new ConfigurationClass(reader, true));
}
}
}
}
/**
* Process the given <code>@PropertySource</code> annotation metadata.
* @param propertySource metadata for the <code>@PropertySource</code> annotation found
* @throws IOException if loading a property source failed
*/
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
String name = propertySource.getString("name");
String[] locations = propertySource.getStringArray("value");
int nLocations = locations.length;
if (nLocations == 0) {
throw new IllegalArgumentException("At least one @PropertySource(value) location is required");
}
for (int i = 0; i < nLocations; i++) {
locations[i] = this.environment.resolveRequiredPlaceholders(locations[i]);
}
ClassLoader classLoader = this.resourceLoader.getClassLoader();
if (!StringUtils.hasText(name)) {
for (String location : locations) {
this.propertySources.push(new ResourcePropertySource(location, classLoader));
}
}
else {
if (nLocations == 1) {
this.propertySources.push(new ResourcePropertySource(name, locations[0], classLoader));
}
else {
CompositePropertySource ps = new CompositePropertySource(name);
for (String location : locations) {
ps.addPropertySource(new ResourcePropertySource(location, classLoader));
}
this.propertySources.push(ps);
}
}
}
/**
* Recursively collect all declared {@code @Import} values. Unlike most
* meta-annotations it is valid to have several {@code @Import}s declared with
@@ -287,69 +321,103 @@ class ConfigurationClassParser {
* <p>For example, it is common for a {@code @Configuration} class to declare direct
* {@code @Import}s in addition to meta-imports originating from an {@code @Enable}
* annotation.
* @param className the class name to search
* @param imports the imports collected so far or {@code null}
* @param visited used to track visited classes to prevent infinite recursion (must not be null)
* @return a set of all {@link Import#value() import values} or {@code null}
* @param metadata the metadata representation of the class to search
* @param imports the imports collected so far
* @param visited used to track visited classes to prevent infinite recursion
* @throws IOException if there is any problem reading metadata from the named class
*/
private Set<String> getImports(String className, Set<String> imports, Set<String> visited) throws IOException {
if (visited.add(className) && !className.startsWith("java")) {
AnnotationMetadata metadata = metadataReaderFactory.getMetadataReader(className).getAnnotationMetadata();
for (String annotationType : metadata.getAnnotationTypes()) {
imports = getImports(annotationType, imports, visited);
private void collectImports(AnnotationMetadata metadata, Set<Object> imports, Set<Object> visited) throws IOException {
String className = metadata.getClassName();
if (visited.add(className)) {
if (metadata instanceof StandardAnnotationMetadata) {
StandardAnnotationMetadata stdMetadata = (StandardAnnotationMetadata) metadata;
for (Annotation ann : stdMetadata.getIntrospectedClass().getAnnotations()) {
if (!ann.annotationType().getName().startsWith("java") && !(ann instanceof Import)) {
collectImports(new StandardAnnotationMetadata(ann.annotationType()), imports, visited);
}
}
Map<String, Object> attributes = stdMetadata.getAnnotationAttributes(Import.class.getName(), false);
if (attributes != null) {
Class[] value = (Class[]) attributes.get("value");
if (!ObjectUtils.isEmpty(value)) {
imports.addAll(Arrays.asList(value));
}
}
}
Map<String, Object> attributes = metadata.getAnnotationAttributes(Import.class.getName(), true);
if (attributes != null) {
String[] value = (String[]) attributes.get("value");
if (value != null && value.length > 0) {
imports = (imports == null ? new LinkedHashSet<String>() : imports);
imports.addAll(Arrays.asList(value));
else {
for (String annotationType : metadata.getAnnotationTypes()) {
if (!className.startsWith("java") && !className.equals(Import.class.getName())) {
try {
collectImports(
new StandardAnnotationMetadata(this.resourceLoader.getClassLoader().loadClass(annotationType)),
imports, visited);
}
catch (ClassNotFoundException ex) {
//
}
}
}
Map<String, Object> attributes = metadata.getAnnotationAttributes(Import.class.getName(), true);
if (attributes != null) {
String[] value = (String[]) attributes.get("value");
if (!ObjectUtils.isEmpty(value)) {
imports.addAll(Arrays.asList(value));
}
}
}
}
return imports;
}
private void processImport(ConfigurationClass configClass, String[] classesToImport, boolean checkForCircularImports) throws IOException {
private void processImport(ConfigurationClass configClass, Collection<?> classesToImport, boolean checkForCircularImports) throws IOException {
if (checkForCircularImports && this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack, configClass.getMetadata()));
}
else {
this.importStack.push(configClass);
AnnotationMetadata importingClassMetadata = configClass.getMetadata();
for (String candidate : classesToImport) {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(candidate);
if (new AssignableTypeFilter(ImportSelector.class).match(reader, this.metadataReaderFactory)) {
// the candidate class is an ImportSelector -> delegate to it to determine imports
try {
ImportSelector selector = BeanUtils.instantiateClass(
this.resourceLoader.getClassLoader().loadClass(candidate), ImportSelector.class);
processImport(configClass, selector.selectImports(importingClassMetadata), false);
try {
for (Object candidate : classesToImport) {
Object candidateToCheck = (candidate instanceof Class ? (Class) candidate :
this.metadataReaderFactory.getMetadataReader((String) candidate));
if (checkAssignability(ImportSelector.class, candidateToCheck)) {
// the candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate :
this.resourceLoader.getClassLoader().loadClass((String) candidate));
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
processImport(configClass, Arrays.asList(selector.selectImports(importingClassMetadata)), false);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(ex);
}
}
else if (new AssignableTypeFilter(ImportBeanDefinitionRegistrar.class).match(reader, this.metadataReaderFactory)) {
// the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions
try {
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(
this.resourceLoader.getClassLoader().loadClass(candidate), ImportBeanDefinitionRegistrar.class);
else if (checkAssignability(ImportBeanDefinitionRegistrar.class, candidateToCheck)) {
// the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions
Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate :
this.resourceLoader.getClassLoader().loadClass((String) candidate));
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
invokeAwareMethods(registrar);
registrar.registerBeanDefinitions(importingClassMetadata, registry);
registrar.registerBeanDefinitions(importingClassMetadata, this.registry);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(ex);
else {
// candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class
this.importStack.registerImport(importingClassMetadata.getClassName(),
(candidate instanceof Class ? ((Class) candidate).getName() : (String) candidate));
processConfigurationClass(candidateToCheck instanceof Class ? new ConfigurationClass((Class) candidateToCheck, true) :
new ConfigurationClass((MetadataReader) candidateToCheck, true));
}
}
else {
// the candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class
this.importStack.registerImport(importingClassMetadata.getClassName(), candidate);
processConfigurationClass(new ConfigurationClass(reader, true));
}
}
this.importStack.pop();
catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to load import candidate class", ex);
}
finally {
this.importStack.pop();
}
}
}
private boolean checkAssignability(Class<?> clazz, Object candidate) throws IOException {
if (candidate instanceof Class) {
return clazz.isAssignableFrom((Class) candidate);
}
else {
return new AssignableTypeFilter(clazz).match((MetadataReader) candidate, this.metadataReaderFactory);
}
}
@@ -393,7 +461,7 @@ class ConfigurationClassParser {
return this.propertySources;
}
public ImportRegistry getImportRegistry() {
ImportRegistry getImportRegistry() {
return this.importStack;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 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.
@@ -36,6 +36,7 @@ abstract class ConfigurationMethod {
this.configurationClass = configurationClass;
}
public MethodMetadata getMetadata() {
return this.metadata;
}
@@ -48,13 +49,22 @@ abstract class ConfigurationMethod {
return new Location(this.configurationClass.getResource(), this.metadata);
}
String getFullyQualifiedMethodName() {
return this.metadata.getDeclaringClassName() + "#" + this.metadata.getMethodName();
}
static String getShortMethodName(String fullyQualifiedMethodName) {
return fullyQualifiedMethodName.substring(fullyQualifiedMethodName.indexOf('#') + 1);
}
public void validate(ProblemReporter problemReporter) {
}
@Override
public String toString() {
return String.format("[%s:name=%s,declaringClass=%s]",
this.getClass().getSimpleName(), this.getMetadata().getMethodName(), this.getMetadata().getDeclaringClassName());
getClass().getSimpleName(), getMetadata().getMethodName(), getMetadata().getDeclaringClassName());
}
}
@@ -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.
@@ -52,9 +52,9 @@ public class GenericApplicationListenerAdapter implements SmartApplicationListen
}
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
Class typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
Class<?> typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
if (typeArg == null || typeArg.equals(ApplicationEvent.class)) {
Class targetClass = AopUtils.getTargetClass(this.delegate);
Class<?> targetClass = AopUtils.getTargetClass(this.delegate);
if (targetClass != this.delegate.getClass()) {
typeArg = GenericTypeResolver.resolveTypeArgument(targetClass, ApplicationListener.class);
}
@@ -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,22 +23,26 @@ import java.lang.annotation.Target;
/**
* Declares that a field should be formatted as a date time.
* Supports formatting by style pattern, ISO date time pattern, or custom format pattern string.
* Can be applied to {@code java.util.Date}, {@code java.util.Calendar}, {@code java.long.Long}, or Joda Time fields.
* <p>
* For style-based formatting, set the {@link #style()} attribute to be the style pattern code.
*
* <p>Supports formatting by style pattern, ISO date time pattern, or custom format pattern string.
* Can be applied to {@code java.util.Date}, {@code java.util.Calendar}, {@code java.long.Long},
* Joda-Time value types; and as of Spring 4 and JDK 8, to JSR-310 <code>java.time</code> types too.
*
* <p>For style-based formatting, set the {@link #style()} attribute to be the style pattern code.
* The first character of the code is the date style, and the second character is the time style.
* Specify a character of 'S' for short style, 'M' for medium, 'L' for long, and 'F' for full.
* A date or time may be omitted by specifying the style character '-'.
* <p>
* For ISO-based formatting, set the {@link #iso()} attribute to be the desired {@link ISO} format, such as {@link ISO#DATE}.
<p>
* For custom formatting, set the {@link #pattern()} attribute to be the DateTime pattern, such as {@code yyyy/MM/dd hh:mm:ss a}.
* <p>
* Each attribute is mutually exclusive, so only set one attribute per annotation instance (the one most convenient one for your formatting needs).
*
* <p>For ISO-based formatting, set the {@link #iso()} attribute to be the desired {@link ISO} format,
* such as {@link ISO#DATE}. For custom formatting, set the {@link #pattern()} attribute to be the
* DateTime pattern, such as {@code yyyy/MM/dd hh:mm:ss a}.
*
* <p>Each attribute is mutually exclusive, so only set one attribute per annotation instance
* (the one most convenient one for your formatting needs).
* When the pattern attribute is specified, it takes precedence over both the style and ISO attribute.
* When the iso attribute is specified, if takes precedence over the style attribute.
* When no annotation attributes are specified, the default format applied is style-based with a style code of 'SS' (short date, short time).
* When no annotation attributes are specified, the default format applied is style-based
* with a style code of 'SS' (short date, short time).
*
* @author Keith Donald
* @author Juergen Hoeller
@@ -51,23 +55,24 @@ public @interface DateTimeFormat {
/**
* The style pattern to use to format the field.
* Defaults to 'SS' for short date time.
* Set this attribute when you wish to format your field in accordance with a common style other than the default style.
* <p>Defaults to 'SS' for short date time. Set this attribute when you wish to format
* your field in accordance with a common style other than the default style.
*/
String style() default "SS";
/**
* The ISO pattern to use to format the field.
* The possible ISO patterns are defined in the {@link ISO} enum.
* Defaults to ISO.NONE, indicating this attribute should be ignored.
* Set this attribute when you wish to format your field in accordance with an ISO date time format.
* <p>Defaults to {@link ISO#NONE}, indicating this attribute should be ignored.
* Set this attribute when you wish to format your field in accordance with an ISO format.
*/
ISO iso() default ISO.NONE;
/**
* The custom pattern to use to format the field.
* Defaults to empty String, indicating no custom pattern String has been specified.
* Set this attribute when you wish to format your field in accordance with a custom date time pattern not represented by a style or ISO format.
* <p>Defaults to empty String, indicating no custom pattern String has been specified.
* Set this attribute when you wish to format your field in accordance with a custom
* date time pattern not represented by a style or ISO format.
*/
String pattern() default "";
@@ -78,18 +83,21 @@ public @interface DateTimeFormat {
public enum ISO {
/**
* The most common ISO Date Format {@code yyyy-MM-dd} e.g. 2000-10-31.
* The most common ISO Date Format {@code yyyy-MM-dd},
* e.g. 2000-10-31.
*/
DATE,
/**
* The most common ISO Time Format {@code HH:mm:ss.SSSZ} e.g. 01:30:00.000-05:00.
* The most common ISO Time Format {@code HH:mm:ss.SSSZ},
* e.g. 01:30:00.000-05:00.
*/
TIME,
/**
* The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSZ} e.g. 2000-10-31 01:30:00.000-05:00.
* The default if no annotation value is specified.
* The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSZ},
* e.g. 2000-10-31 01:30:00.000-05:00.
* <p>This is the default if no annotation value is specified.
*/
DATE_TIME,
@@ -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.
@@ -46,7 +46,7 @@ public class DateFormatter implements Formatter<Date> {
private static final Map<ISO, String> ISO_PATTERNS;
static {
Map<ISO, String> formats = new HashMap<DateTimeFormat.ISO, String>();
Map<ISO, String> formats = new HashMap<DateTimeFormat.ISO, String>(4);
formats.put(ISO.DATE, "yyyy-MM-dd");
formats.put(ISO.TIME, "HH:mm:ss.SSSZ");
formats.put(ISO.DATE_TIME, "yyyy-MM-dd'T'HH:mm:ss.SSSZ");
@@ -89,6 +89,15 @@ public class DateFormatter implements Formatter<Date> {
this.pattern = pattern;
}
/**
* Set the ISO format used for this date.
* @param iso the {@link ISO} format
* @since 3.2
*/
public void setIso(ISO iso) {
this.iso = iso;
}
/**
* Set the style to use to format date values.
* <p>If not specified, DateFormat's default style will be used.
@@ -112,7 +121,7 @@ public class DateFormatter implements Formatter<Date> {
* <li>'F' = Full</li>
* <li>'-' = Omitted</li>
* <ul>
* This method mimics the styles supported by Joda Time.
* This method mimics the styles supported by Joda-Time.
* @param stylePattern two characters from the set {"S", "M", "L", "F", "-"}
* @since 3.2
*/
@@ -120,14 +129,6 @@ public class DateFormatter implements Formatter<Date> {
this.stylePattern = stylePattern;
}
/**
* Set the ISO format used for this date.
* @param iso the {@link ISO} format
* @since 3.2
*/
public void setIso(ISO iso) {
this.iso = iso;
}
/**
* Set the TimeZone to normalize the date values into, if any.
*/
@@ -204,4 +205,5 @@ public class DateFormatter implements Formatter<Date> {
}
throw new IllegalStateException("Unsupported style pattern '"+ stylePattern+ "'");
}
}
@@ -27,8 +27,8 @@ import org.springframework.util.Assert;
/**
* Configures Date formatting for use with Spring.
* <p>
* Designed for direct instantiation but also exposes the static
*
* <p>Designed for direct instantiation but also exposes the static
* {@link #addDateConverters(ConverterRegistry)} utility method for ad hoc use
* against any {@code ConverterRegistry} instance.
*
@@ -39,10 +39,20 @@ import org.springframework.util.Assert;
*/
public class DateFormatterRegistrar implements FormatterRegistrar {
private DateFormatter dateFormatter;
/**
* Set the date formatter to register. If not specified no formatter is registered.
* This method can be used if global formatter configuration is required.
* @param dateFormatter the date formatter
*/
public void setFormatter(DateFormatter dateFormatter) {
Assert.notNull(dateFormatter, "DateFormatter must not be null");
this.dateFormatter = dateFormatter;
}
public void registerFormatters(FormatterRegistry registry) {
addDateConverters(registry);
registry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory());
@@ -55,16 +65,6 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
}
}
/**
* Set the date formatter to register. If not specified no formatter is registered.
* This method can be used if global formatter configuration is required.
* @param dateFormatter the date formatter
*/
public void setFormatter(DateFormatter dateFormatter) {
Assert.notNull(dateFormatter, "DateFormatter must not be null");
this.dateFormatter = dateFormatter;
}
/**
* Add date converters to the specified registry.
* @param converterRegistry the registry of converters to add to
@@ -80,6 +80,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
private static class DateToLongConverter implements Converter<Date, Long> {
public Long convert(Date source) {
return source.getTime();
}
@@ -87,6 +88,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
private static class DateToCalendarConverter implements Converter<Date, Calendar> {
public Calendar convert(Date source) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(source);
@@ -96,6 +98,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
private static class CalendarToDateConverter implements Converter<Calendar, Date> {
public Date convert(Calendar source) {
return source.getTime();
}
@@ -103,6 +106,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
private static class CalendarToLongConverter implements Converter<Calendar, Long> {
public Long convert(Calendar source) {
return source.getTime().getTime();
}
@@ -110,6 +114,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
private static class LongToDateConverter implements Converter<Long, Date> {
public Date convert(Long source) {
return new Date(source);
}
@@ -118,10 +123,11 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
private static class LongToCalendarConverter implements Converter<Long, Calendar> {
private DateToCalendarConverter dateToCalendarConverter = new DateToCalendarConverter();
private final DateToCalendarConverter dateToCalendarConverter = new DateToCalendarConverter();
public Calendar convert(Long source) {
return this.dateToCalendarConverter.convert(new Date(source));
}
}
}
@@ -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.
@@ -44,7 +44,7 @@ public class DateTimeFormatAnnotationFormatterFactory implements
private static final Set<Class<?>> FIELD_TYPES;
static {
Set<Class<?>> fieldTypes = new HashSet<Class<?>>();
Set<Class<?>> fieldTypes = new HashSet<Class<?>>(4);
fieldTypes.add(Date.class);
fieldTypes.add(Calendar.class);
fieldTypes.add(Long.class);
@@ -82,4 +82,5 @@ public class DateTimeFormatAnnotationFormatterFactory implements
protected String resolveEmbeddedValue(String value) {
return (this.embeddedValueResolver != null ? this.embeddedValueResolver.resolveStringValue(value) : value);
}
}
@@ -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,32 +22,34 @@ import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.util.StringUtils;
/**
* Factory that creates a Joda {@link DateTimeFormatter}. Formatters will be
* created using the defined {@link #setPattern(String) pattern}, {@link #setIso ISO},
* or {@link #setStyle(String) style} (considered in that order).
* Factory that creates a Joda-Time {@link DateTimeFormatter}.
*
* <p>Formatters will be created using the defined {@link #setPattern pattern},
* {@link #setIso ISO}, and {@link #setStyle style} methods (considered in that order).
*
* @author Phillip Webb
* @author Sam Brannen
* @since 3.2
* @see #createDateTimeFormatter()
* @see #createDateTimeFormatter(DateTimeFormatter)
* @see #setPattern(String)
* @see #setPattern
* @see #setStyle
* @see #setIso
* @see #setStyle(String)
* @see DateTimeFormatterFactoryBean
*/
public class DateTimeFormatterFactory {
private String pattern;
private ISO iso;
private String style;
private String pattern;
private TimeZone timeZone;
@@ -67,9 +69,50 @@ public class DateTimeFormatterFactory {
/**
* Create a new {@code DateTimeFormatter} using this factory. If no specific
* {@link #setStyle(String) style}, {@link #setIso ISO}, or
* {@link #setPattern(String) pattern} have been defined the
* Set the pattern to use to format date values.
* @param pattern the format pattern
*/
public void setPattern(String pattern) {
this.pattern = pattern;
}
/**
* Set the ISO format used to format date values.
* @param iso the ISO format
*/
public void setIso(ISO iso) {
this.iso = iso;
}
/**
* Set the two characters to use to format date values, in Joda-Time style.
* <p>The first character is used for the date style; the second is for
* the time style. Supported characters are:
* <ul>
* <li>'S' = Small</li>
* <li>'M' = Medium</li>
* <li>'L' = Long</li>
* <li>'F' = Full</li>
* <li>'-' = Omitted</li>
* </ul>
* @param style two characters from the set {"S", "M", "L", "F", "-"}
*/
public void setStyle(String style) {
this.style = style;
}
/**
* Set the {@code TimeZone} to normalize the date values into, if any.
* @param timeZone the time zone
*/
public void setTimeZone(TimeZone timeZone) {
this.timeZone = timeZone;
}
/**
* Create a new {@code DateTimeFormatter} using this factory.
* <p>If no specific pattern or style has been defined,
* {@link DateTimeFormat#mediumDateTime() medium date time format} will be used.
* @return a new date time formatter
* @see #createDateTimeFormatter(DateTimeFormatter)
@@ -79,21 +122,20 @@ public class DateTimeFormatterFactory {
}
/**
* Create a new {@code DateTimeFormatter} using this factory. If no specific
* {@link #setStyle(String) style}, {@link #setIso ISO}, or
* {@link #setPattern(String) pattern} have been defined the supplied
* {@code fallbackFormatter} will be used.
* @param fallbackFormatter the fall-back formatter to use when no specific factory
* properties have been set (can be {@code null}).
* Create a new {@code DateTimeFormatter} using this factory.
* <p>If no specific pattern or style has been defined,
* the supplied {@code fallbackFormatter} will be used.
* @param fallbackFormatter the fall-back formatter to use when no specific
* factory properties have been set (can be {@code null}).
* @return a new date time formatter
*/
public DateTimeFormatter createDateTimeFormatter(DateTimeFormatter fallbackFormatter) {
DateTimeFormatter dateTimeFormatter = null;
if (StringUtils.hasLength(pattern)) {
dateTimeFormatter = DateTimeFormat.forPattern(pattern);
if (StringUtils.hasLength(this.pattern)) {
dateTimeFormatter = DateTimeFormat.forPattern(this.pattern);
}
else if (iso != null && iso != ISO.NONE) {
switch (iso) {
else if (this.iso != null && this.iso != ISO.NONE) {
switch (this.iso) {
case DATE:
dateTimeFormatter = ISODateTimeFormat.date();
break;
@@ -107,11 +149,11 @@ public class DateTimeFormatterFactory {
/* no-op */
break;
default:
throw new IllegalStateException("Unsupported ISO format: " + iso);
throw new IllegalStateException("Unsupported ISO format: " + this.iso);
}
}
else if (StringUtils.hasLength(style)) {
dateTimeFormatter = DateTimeFormat.forStyle(style);
else if (StringUtils.hasLength(this.style)) {
dateTimeFormatter = DateTimeFormat.forStyle(this.style);
}
if (dateTimeFormatter != null && this.timeZone != null) {
@@ -120,44 +162,4 @@ public class DateTimeFormatterFactory {
return (dateTimeFormatter != null ? dateTimeFormatter : fallbackFormatter);
}
/**
* Set the {@code TimeZone} to normalize the date values into, if any.
* @param timeZone the time zone
*/
public void setTimeZone(TimeZone timeZone) {
this.timeZone = timeZone;
}
/**
* Set the two characters to use to format date values. The first character is used for
* the date style; the second is for the time style. Supported characters are:
* <ul>
* <li>'S' = Small</li>
* <li>'M' = Medium</li>
* <li>'L' = Long</li>
* <li>'F' = Full</li>
* <li>'-' = Omitted</li>
* </ul>
* <p>This method mimics the styles supported by Joda Time.
* @param style two characters from the set {"S", "M", "L", "F", "-"}
*/
public void setStyle(String style) {
this.style = style;
}
/**
* Set the ISO format used to format date values.
* @param iso the ISO format
*/
public void setIso(ISO iso) {
this.iso = iso;
}
/**
* Set the pattern to use to format date values.
* @param pattern the format pattern
*/
public void setPattern(String pattern) {
this.pattern = pattern;
}
}
@@ -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,15 +22,15 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
/**
* {@link FactoryBean} that creates a Joda {@link DateTimeFormatter}. See the
* {@linkplain DateTimeFormatterFactory base class} for configuration details.
* {@link FactoryBean} that creates a Joda-Time {@link DateTimeFormatter}.
* See the {@link DateTimeFormatterFactory base class} for configuration details.
*
* @author Phillip Webb
* @author Sam Brannen
* @since 3.2
* @see #setPattern(String)
* @see #setIso(org.springframework.format.annotation.DateTimeFormat.ISO)
* @see #setStyle(String)
* @see #setPattern
* @see #setIso
* @see #setStyle
* @see DateTimeFormatterFactory
*/
public class DateTimeFormatterFactoryBean extends DateTimeFormatterFactory
@@ -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.
@@ -56,7 +56,7 @@ public class JodaDateTimeFormatAnnotationFormatterFactory
// (if we did not do this, the default byType rules for LocalDate, LocalTime,
// and LocalDateTime would take precedence over the annotation rule, which
// is not what we want)
Set<Class<?>> fieldTypes = new HashSet<Class<?>>(7);
Set<Class<?>> fieldTypes = new HashSet<Class<?>>(8);
fieldTypes.add(ReadableInstant.class);
fieldTypes.add(LocalDate.class);
fieldTypes.add(LocalTime.class);
@@ -71,10 +71,6 @@ public class JodaDateTimeFormatAnnotationFormatterFactory
private StringValueResolver embeddedValueResolver;
public final Set<Class<?>> getFieldTypes() {
return FIELD_TYPES;
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.embeddedValueResolver = resolver;
}
@@ -83,20 +79,24 @@ public class JodaDateTimeFormatAnnotationFormatterFactory
return (this.embeddedValueResolver != null ? this.embeddedValueResolver.resolveStringValue(value) : value);
}
public final Set<Class<?>> getFieldTypes() {
return FIELD_TYPES;
}
public Printer<?> getPrinter(DateTimeFormat annotation, Class<?> fieldType) {
DateTimeFormatter formatter = getFormatter(annotation, fieldType);
if (ReadableInstant.class.isAssignableFrom(fieldType)) {
return new ReadableInstantPrinter(formatter);
}
if (ReadablePartial.class.isAssignableFrom(fieldType)) {
return new ReadablePartialPrinter(formatter);
}
if (Calendar.class.isAssignableFrom(fieldType)) {
else if (ReadableInstant.class.isAssignableFrom(fieldType) || Calendar.class.isAssignableFrom(fieldType)) {
// assumes Calendar->ReadableInstant converter is registered
return new ReadableInstantPrinter(formatter);
}
// assumes Date->Long converter is registered
return new MillisecondInstantPrinter(formatter);
else {
// assumes Date->Long converter is registered
return new MillisecondInstantPrinter(formatter);
}
}
public Parser<DateTime> getParser(DateTimeFormat annotation, Class<?> fieldType) {
@@ -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,8 +21,10 @@ import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormatter;
/**
* A context that holds user-specific Joda Time settings such as the user's Chronology (calendar system) and time zone.
* A {@code null} property value indicate the user has not specified a setting.
* A context that holds user-specific Joda-Time settings such as the user's
* Chronology (calendar system) and time zone.
*
* <p>A {@code null} property value indicate the user has not specified a setting.
*
* @author Keith Donald
* @since 3.0
@@ -43,8 +45,7 @@ public class JodaTimeContext {
}
/**
* The user's chronology (calendar system).
* Null if not specified.
* The user's chronology (calendar system), if any.
*/
public Chronology getChronology() {
return this.chronology;
@@ -58,8 +59,7 @@ public class JodaTimeContext {
}
/**
* The user's timezone.
* Null if not specified.
* The user's timezone, if any.
*/
public DateTimeZone getTimeZone() {
return timeZone;
@@ -67,9 +67,11 @@ public class JodaTimeContext {
/**
* Gets the Formatter with the this context's settings applied to the base {@code formatter}.
* @param formatter the base formatter that establishes default formatting rules, generally context independent
* @return the context DateTimeFormatter
* Get the DateTimeFormatter with the this context's settings
* applied to the base {@code formatter}.
* @param formatter the base formatter that establishes default
* formatting rules, generally context-independent
* @return the contextual DateTimeFormatter
*/
public DateTimeFormatter getFormatter(DateTimeFormatter formatter) {
if (this.chronology != null) {
@@ -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,7 +23,8 @@ import org.joda.time.format.DateTimeFormatter;
import org.springframework.core.NamedThreadLocal;
/**
* A holder for a thread-local user {@link JodaTimeContext}.
* A holder for a thread-local {@link JodaTimeContext}
* with user-specific Joda-Time settings.
*
* @author Keith Donald
* @author Juergen Hoeller
@@ -27,12 +27,14 @@ import org.joda.time.LocalDateTime;
import org.joda.time.LocalTime;
import org.joda.time.MutableDateTime;
import org.joda.time.ReadableInstant;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterRegistry;
import org.springframework.format.datetime.DateFormatterRegistrar;
/**
* Installs lower-level type converters required to integrate Joda Time support into Spring's field formatting system.
* Installs lower-level type converters required to integrate
* Joda-Time support into Spring's field formatting system.
*
* @author Keith Donald
* @author Phillip Webb
@@ -50,116 +52,87 @@ final class JodaTimeConverters {
registry.addConverter(new DateTimeToLocalTimeConverter());
registry.addConverter(new DateTimeToLocalDateTimeConverter());
registry.addConverter(new DateTimeToDateMidnightConverter());
registry.addConverter(new DateTimeToInstantConverter());
registry.addConverter(new DateTimeToMutableDateTimeConverter());
registry.addConverter(new DateTimeToInstantConverter());
registry.addConverter(new DateTimeToDateConverter());
registry.addConverter(new DateTimeToCalendarConverter());
registry.addConverter(new DateTimeToLongConverter());
registry.addConverter(new CalendarToReadableInstantConverter());
registry.addConverter(new DateToReadableInstantConverter());
registry.addConverter(new CalendarToReadableInstantConverter());
}
/**
* Used when binding a parsed DateTime to a LocalDate field.
* @see DateTimeParser
**/
private static class DateTimeToLocalDateConverter implements Converter<DateTime, LocalDate> {
public LocalDate convert(DateTime source) {
return source.toLocalDate();
}
}
/**
* Used when binding a parsed DateTime to a LocalTime field.
* @see DateTimeParser
*/
private static class DateTimeToLocalTimeConverter implements Converter<DateTime, LocalTime> {
public LocalTime convert(DateTime source) {
return source.toLocalTime();
}
}
/**
* Used when binding a parsed DateTime to a LocalDateTime field.
* @see DateTimeParser
*/
private static class DateTimeToLocalDateTimeConverter implements Converter<DateTime, LocalDateTime> {
public LocalDateTime convert(DateTime source) {
return source.toLocalDateTime();
}
}
/**
* Used when binding a parsed DateTime to a DateMidnight field.
* @see DateTimeParser
*/
private static class DateTimeToDateMidnightConverter implements Converter<DateTime, DateMidnight> {
public DateMidnight convert(DateTime source) {
return source.toDateMidnight();
}
}
/**
* Used when binding a parsed DateTime to an Instant field.
* @see DateTimeParser
*/
private static class DateTimeToInstantConverter implements Converter<DateTime, Instant> {
public Instant convert(DateTime source) {
return source.toInstant();
}
}
/**
* Used when binding a parsed DateTime to a MutableDateTime field.
* @see DateTimeParser
*/
private static class DateTimeToMutableDateTimeConverter implements Converter<DateTime, MutableDateTime> {
public MutableDateTime convert(DateTime source) {
return source.toMutableDateTime();
}
}
/**
* Used when binding a parsed DateTime to a java.util.Date field.
* @see DateTimeParser
*/
private static class DateTimeToInstantConverter implements Converter<DateTime, Instant> {
public Instant convert(DateTime source) {
return source.toInstant();
}
}
private static class DateTimeToDateConverter implements Converter<DateTime, Date> {
public Date convert(DateTime source) {
return source.toDate();
}
}
/**
* Used when binding a parsed DateTime to a java.util.Calendar field.
* @see DateTimeParser
*/
private static class DateTimeToCalendarConverter implements Converter<DateTime, Calendar> {
public Calendar convert(DateTime source) {
return source.toGregorianCalendar();
}
}
/**
* Used when binding a parsed DateTime to a java.lang.Long field.
* @see DateTimeParser
*/
private static class DateTimeToLongConverter implements Converter<DateTime, Long> {
public Long convert(DateTime source) {
return source.getMillis();
}
}
/**
* Used when printing a java.util.Calendar field with a ReadableInstantPrinter.
* @see MillisecondInstantPrinter
* @see JodaDateTimeFormatAnnotationFormatterFactory
*/
private static class CalendarToReadableInstantConverter implements Converter<Calendar, ReadableInstant> {
public ReadableInstant convert(Calendar source) {
return new DateTime(source);
}
}
/**
* Used when printing a java.util.Date field with a ReadableInstantPrinter.
@@ -167,8 +140,23 @@ final class JodaTimeConverters {
* @see JodaDateTimeFormatAnnotationFormatterFactory
*/
private static class DateToReadableInstantConverter implements Converter<Date, ReadableInstant> {
public ReadableInstant convert(Date source) {
return new DateTime(source);
}
}
/**
* Used when printing a java.util.Calendar field with a ReadableInstantPrinter.
* @see MillisecondInstantPrinter
* @see JodaDateTimeFormatAnnotationFormatterFactory
*/
private static class CalendarToReadableInstantConverter implements Converter<Calendar, ReadableInstant> {
public ReadableInstant convert(Calendar source) {
return new DateTime(source);
}
}
}
@@ -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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.format.datetime.joda;
import java.util.Calendar;
@@ -35,7 +36,7 @@ import org.springframework.format.Printer;
import org.springframework.format.annotation.DateTimeFormat.ISO;
/**
* Configures Joda Time's formatting system for use with Spring.
* Configures Joda-Time's formatting system for use with Spring.
*
* @author Keith Donald
* @author Juergen Hoeller
@@ -51,15 +52,18 @@ import org.springframework.format.annotation.DateTimeFormat.ISO;
*/
public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
private static enum Type {DATE, TIME, DATE_TIME}
/**
* User defined formatters.
*/
private Map<Type, DateTimeFormatter> formatters = new HashMap<Type, DateTimeFormatter>();
private final Map<Type, DateTimeFormatter> formatters = new HashMap<Type, DateTimeFormatter>();
/**
* Factories used when specific formatters have not been specified.
*/
private Map<Type, DateTimeFormatterFactory> factories;
private final Map<Type, DateTimeFormatterFactory> factories;
public JodaTimeFormatterRegistrar() {
@@ -70,12 +74,24 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
}
/**
* Set whether standard ISO formatting should be applied to all date/time types.
* Default is "false" (no).
* <p>If set to "true", the "dateStyle", "timeStyle" and "dateTimeStyle"
* properties are effectively ignored.
*/
public void setUseIsoFormat(boolean useIsoFormat) {
this.factories.get(Type.DATE).setIso(useIsoFormat ? ISO.DATE : null);
this.factories.get(Type.TIME).setIso(useIsoFormat ? ISO.TIME : null);
this.factories.get(Type.DATE_TIME).setIso(useIsoFormat ? ISO.DATE_TIME : null);
}
/**
* Set the default format style of Joda {@link LocalDate} objects.
* Default is {@link DateTimeFormat#shortDate()}.
*/
public void setDateStyle(String dateStyle) {
this.factories.get(Type.DATE).setStyle(dateStyle+"-");
this.factories.get(Type.DATE).setStyle(dateStyle + "-");
}
/**
@@ -83,7 +99,7 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
* Default is {@link DateTimeFormat#shortTime()}.
*/
public void setTimeStyle(String timeStyle) {
this.factories.get(Type.TIME).setStyle("-"+timeStyle);
this.factories.get(Type.TIME).setStyle("-" + timeStyle);
}
/**
@@ -95,25 +111,14 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
this.factories.get(Type.DATE_TIME).setStyle(dateTimeStyle);
}
/**
* Set whether standard ISO formatting should be applied to all Date/Time types.
* Default is false (no).
* If set to true, the dateStyle, timeStyle, and dateTimeStyle properties are ignored.
*/
public void setUseIsoFormat(boolean useIsoFormat) {
this.factories.get(Type.DATE).setIso(useIsoFormat ? ISO.DATE : null);
this.factories.get(Type.TIME).setIso(useIsoFormat ? ISO.TIME : null);
this.factories.get(Type.DATE_TIME).setIso(useIsoFormat ? ISO.DATE_TIME : null);
}
/**
* Set the formatter that will be used for objects representing date values.
* <p>This formatter will be used for the {@link LocalDate} type. When specified
* the {@link #setDateStyle(String) dateStyle} and
* {@link #setUseIsoFormat(boolean) useIsoFormat} properties will be ignored.
* @param formatter the formatter to use
* @see #setTimeFormatter(DateTimeFormatter)
* @see #setDateTimeFormatter(DateTimeFormatter)
* @see #setTimeFormatter
* @see #setDateTimeFormatter
* @since 3.2
*/
public void setDateFormatter(DateTimeFormatter formatter) {
@@ -126,8 +131,8 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
* the {@link #setTimeStyle(String) timeStyle} and
* {@link #setUseIsoFormat(boolean) useIsoFormat} properties will be ignored.
* @param formatter the formatter to use
* @see #setDateFormatter(DateTimeFormatter)
* @see #setDateTimeFormatter(DateTimeFormatter)
* @see #setDateFormatter
* @see #setDateTimeFormatter
* @since 3.2
*/
public void setTimeFormatter(DateTimeFormatter formatter) {
@@ -141,14 +146,15 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
* the {@link #setDateTimeStyle(String) dateTimeStyle} and
* {@link #setUseIsoFormat(boolean) useIsoFormat} properties will be ignored.
* @param formatter the formatter to use
* @see #setDateFormatter(DateTimeFormatter)
* @see #setTimeFormatter(DateTimeFormatter)
* @see #setDateFormatter
* @see #setTimeFormatter
* @since 3.2
*/
public void setDateTimeFormatter(DateTimeFormatter formatter) {
this.formatters.put(Type.DATE_TIME, formatter);
}
public void registerFormatters(FormatterRegistry registry) {
JodaTimeConverters.registerConverters(registry);
@@ -176,26 +182,25 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
new DateTimeParser(dateTimeFormatter),
ReadableInstant.class);
// In order to retain back compatibility we only register Date/Calendar
// In order to retain backwards compatibility we only register Date/Calendar
// types when a user defined formatter is specified (see SPR-10105)
if(this.formatters.containsKey(Type.DATE_TIME)) {
if( this.formatters.containsKey(Type.DATE_TIME)) {
addFormatterForFields(registry,
new ReadableInstantPrinter(dateTimeFormatter),
new DateTimeParser(dateTimeFormatter),
Date.class, Calendar.class);
}
registry.addFormatterForFieldAnnotation(
new JodaDateTimeFormatAnnotationFormatterFactory());
registry.addFormatterForFieldAnnotation(new JodaDateTimeFormatAnnotationFormatterFactory());
}
private DateTimeFormatter getFormatter(Type type) {
DateTimeFormatter formatter = this.formatters.get(type);
if(formatter != null) {
if (formatter != null) {
return formatter;
}
DateTimeFormatter fallbackFormatter = getFallbackFormatter(type);
return this.factories.get(type).createDateTimeFormatter(fallbackFormatter );
return this.factories.get(type).createDateTimeFormatter(fallbackFormatter);
}
private DateTimeFormatter getFallbackFormatter(Type type) {
@@ -208,10 +213,10 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
private void addFormatterForFields(FormatterRegistry registry, Printer<?> printer,
Parser<?> parser, Class<?>... fieldTypes) {
for (Class<?> fieldType : fieldTypes) {
registry.addFormatterForFieldType(fieldType, printer, parser);
}
}
private static enum Type {DATE, TIME, DATE_TIME}
}
@@ -1,4 +1,4 @@
/**
* Integration with the Joda Time for formatting Joda types as well as standard JDK Date types.
* Integration with Joda-Time for formatting Joda date and time types as well as standard JDK Date types.
*/
package org.springframework.format.datetime.joda;
@@ -16,12 +16,12 @@
package org.springframework.scheduling.support;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import java.util.Date;
import java.util.TimeZone;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
/**
* {@link Trigger} implementation for cron expressions.
* Wraps a {@link CronSequenceGenerator}.
@@ -55,6 +55,12 @@ public class CronTrigger implements Trigger {
}
/**
* Determine the next execution time according to the given trigger context.
* <p>Next execution times are calculated based on the
* {@linkplain TriggerContext#lastCompletionTime completion time} of the
* previous execution; therefore, overlapping executions won't occur.
*/
public Date nextExecutionTime(TriggerContext triggerContext) {
Date date = triggerContext.lastCompletionTime();
if (date != null) {
@@ -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.
@@ -51,6 +51,12 @@ import org.springframework.util.CollectionUtils;
* you will almost always use the default Validator anyway. This can also be injected directly
* into any target dependency of type {@link org.springframework.validation.Validator}!
*
* <p><b>NOTE: This class is based on Bean Validation 1.0 and (optionally) Hibernate Validator 4.x.</b>
* Nevertheless, its core functionality does work against Bean Validation 1.1 at runtime.
* However, there is no special support for Hibernate Validator 5.0 yet; as a consequence,
* {@link #setValidationMessageSource} won't work in that scenario. Please stick with
* Hibernate Validator 4.3 for the time being, or upgrade to Spring Framework 4.0.
*
* @author Juergen Hoeller
* @since 3.0
* @see javax.validation.ValidatorFactory
@@ -217,10 +223,23 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
configuration.addProperty(entry.getKey(), entry.getValue());
}
// Allow for custom post-processing before we actually build the ValidatorFactory.
postProcessConfiguration(configuration);
this.validatorFactory = configuration.buildValidatorFactory();
setTargetValidator(this.validatorFactory.getValidator());
}
/**
* Post-process the given Bean Validation configuration,
* adding to or overriding any of its settings.
* <p>Invoked right before building the {@link ValidatorFactory}.
* @param configuration the Configuration object, pre-populated with
* settings driven by LocalValidatorFactoryBean's properties
*/
protected void postProcessConfiguration(Configuration configuration) {
}
public Validator getValidator() {
return this.validatorFactory.getValidator();
@@ -244,7 +263,7 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
/**
* Inner class to avoid a hard-coded Hibernate Validator 4.1 dependency.
* Inner class to avoid a hard-coded Hibernate Validator 4.1+ dependency.
*/
private static class HibernateValidatorDelegate {
@@ -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.
@@ -48,9 +48,10 @@ import org.springframework.validation.annotation.Validated;
* inline constraint annotations. Validation groups can be specified through {@code @Validated}
* as well. By default, JSR-303 will validate against its default group only.
*
* <p>As of Spring 3.1, this functionality requires Hibernate Validator 4.2 or higher.
* In a future version of Spring, this class will autodetect a Bean Validation 1.1 compliant
* provider and automatically use the standard method validation support when available.
* <p>As of Spring 3.1, this functionality requires Hibernate Validator 4.2 or 4.3.
* In Spring 4.0, this class will autodetect a Bean Validation 1.1 compliant provider
* (such as Hibernate Validator 5.0) and automatically use the standard method
* validation support when available.
*
* @author Juergen Hoeller
* @since 3.1
@@ -79,7 +79,7 @@ public class ImportedConfigurationClassEnhancementTests {
@Test(expected=BeanDefinitionParsingException.class)
public void importingAnNonConfigurationClassCausesIllegalArgumentException() {
public void importingNonConfigurationClassCausesBeanDefinitionParsingException() {
new AnnotationConfigApplicationContext(ConfigThatImportsNonConfigClass.class);
}
}
@@ -103,5 +103,5 @@ class ConfigThatDoesImport extends Config { }
class ConfigThatDoesNotImport extends Config { }
@Configuration
@Import(Void.class)
@Import(TestBean.class)
class ConfigThatImportsNonConfigClass { }
@@ -0,0 +1,33 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.annotation.spr10546;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
*
* @author Rob Winch
*/
@Configuration
public class ImportedConfig {
@Bean
public String myBean() {
return "myBean";
}
}
@@ -0,0 +1,34 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.annotation.spr10546;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
*
* @author Rob Winch
*/
@Configuration
public class ParentConfig {
@Bean
public String myBean() {
return "myBean";
}
}
@@ -0,0 +1,32 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.annotation.spr10546;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.spr10546.scanpackage.AEnclosingConfig;
/**
*
* @author Rob Winch
*/
@Configuration
@ComponentScan(basePackageClasses=AEnclosingConfig.class)
public class ParentWithComponentScanConfig {
}
@@ -0,0 +1,31 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.annotation.spr10546;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
*
* @author Rob Winch
*/
@Configuration
@Import(ImportedConfig.class)
public class ParentWithImportConfig {
}
@@ -0,0 +1,31 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.annotation.spr10546;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
/**
*
* @author Rob Winch
*/
@Configuration
@ImportResource("classpath:org/springframework/context/annotation/spr10546/importedResource.xml")
public class ParentWithImportResourceConfig {
}
@@ -0,0 +1,29 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.annotation.spr10546;
import org.springframework.context.annotation.Configuration;
/**
*
* @author Rob Winch
*/
@Configuration
public class ParentWithParentConfig extends ParentConfig {
}
@@ -0,0 +1,149 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.annotation.spr10546;
import org.junit.After;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.spr10546.scanpackage.AEnclosingConfig;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
/**
*
* @author Rob Winch
*/
public class Spr10546Tests {
private ConfigurableApplicationContext context;
@After
public void closeContext() {
if(context != null) {
context.close();
}
}
// These fail prior to fixing SPR-10546
@Test
public void enclosingConfigFirstParentDefinesBean() {
assertLoadsMyBean(AEnclosingConfig.class,AEnclosingConfig.ChildConfig.class);
}
/**
* Prior to fixing SPR-10546 this might have succeeded depending on the ordering the
* classes were picked up. If they are picked up in the same order as
* {@link #enclosingConfigFirstParentDefinesBean()} then it would fail. This test is
* mostly for illustration purposes, but doesn't hurt to continue using it.
*
* <p>We purposely use the {@link AEnclosingConfig} to make it alphabetically prior to the
* {@link AEnclosingConfig.ChildConfig} which encourages this to occur with the
* classpath scanning implementation being used by the author of this test.
*/
@Test
public void enclosingConfigFirstParentDefinesBeanWithScanning() {
AnnotationConfigApplicationContext ctx= new AnnotationConfigApplicationContext();
context = ctx;
ctx.scan(AEnclosingConfig.class.getPackage().getName());
ctx.refresh();
assertThat(context.getBean("myBean",String.class), equalTo("myBean"));
}
@Test
public void enclosingConfigFirstParentDefinesBeanWithImportResource() {
assertLoadsMyBean(AEnclosingWithImportResourceConfig.class,AEnclosingWithImportResourceConfig.ChildConfig.class);
}
@Configuration
static class AEnclosingWithImportResourceConfig {
@Configuration
public static class ChildConfig extends ParentWithImportResourceConfig {}
}
@Test
public void enclosingConfigFirstParentDefinesBeanWithComponentScan() {
assertLoadsMyBean(AEnclosingWithComponentScanConfig.class,AEnclosingWithComponentScanConfig.ChildConfig.class);
}
@Configuration
static class AEnclosingWithComponentScanConfig {
@Configuration
public static class ChildConfig extends ParentWithComponentScanConfig {}
}
@Test
public void enclosingConfigFirstParentWithParentDefinesBean() {
assertLoadsMyBean(AEnclosingWithGrandparentConfig.class,AEnclosingWithGrandparentConfig.ChildConfig.class);
}
@Configuration
static class AEnclosingWithGrandparentConfig {
@Configuration
public static class ChildConfig extends ParentWithParentConfig {}
}
@Test
public void importChildConfigThenChildConfig() {
assertLoadsMyBean(ImportChildConfig.class,ChildConfig.class);
}
@Configuration
static class ChildConfig extends ParentConfig {}
@Configuration
@Import(ChildConfig.class)
static class ImportChildConfig {}
// These worked prior, but validating they continue to work
@Test
public void enclosingConfigFirstParentDefinesBeanWithImport() {
assertLoadsMyBean(AEnclosingWithImportConfig.class,AEnclosingWithImportConfig.ChildConfig.class);
}
@Configuration
static class AEnclosingWithImportConfig {
@Configuration
public static class ChildConfig extends ParentWithImportConfig {}
}
@Test
public void childConfigFirst() {
assertLoadsMyBean(AEnclosingConfig.ChildConfig.class, AEnclosingConfig.class);
}
@Test
public void enclosingConfigOnly() {
assertLoadsMyBean(AEnclosingConfig.class);
}
@Test
public void childConfigOnly() {
assertLoadsMyBean(AEnclosingConfig.ChildConfig.class);
}
private void assertLoadsMyBean(Class<?>... annotatedClasses) {
context = new AnnotationConfigApplicationContext(annotatedClasses);
assertThat(context.getBean("myBean",String.class), equalTo("myBean"));
}
}
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myBean" class="java.lang.String" c:_0="myBean"/>
</beans>
@@ -0,0 +1,34 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.annotation.spr10546.scanpackage;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.spr10546.ParentConfig;
/**
* Note the name of {@link AEnclosingConfig} is chosen to help ensure scanning picks up
* the enclosing configuration prior to {@link ChildConfig} to demonstrate this can happen
* with classpath scanning.
*
* @author Rob Winch
*/
@Configuration
public class AEnclosingConfig {
@Configuration
public static class ChildConfig extends ParentConfig {}
}
@@ -26,8 +26,6 @@ import org.joda.time.format.DateTimeFormatter;
import org.junit.Test;
/**
* Tests for {@link DateTimeFormatterFactoryBean}.
*
* @author Phillip Webb
* @author Sam Brannen
*/
@@ -60,4 +58,5 @@ public class DateTimeFormatterFactoryBeanTests {
factory.setStyle("LL");
assertThat(factory.getObject(), is(sameInstance(formatter)));
}
}
@@ -30,8 +30,6 @@ import org.junit.Test;
import org.springframework.format.annotation.DateTimeFormat.ISO;
/**
* Tests for {@link DateTimeFormatterFactory}.
*
* @author Phillip Webb
* @author Sam Brannen
*/
@@ -100,4 +98,5 @@ public class DateTimeFormatterFactoryTests {
private DateTimeFormatter applyLocale(DateTimeFormatter dateTimeFormatter) {
return dateTimeFormatter.withLocale(Locale.US);
}
}
@@ -116,7 +116,7 @@ public class JodaTimeFormattingTests {
}
@Test
public void testBindLocalDateWithSpecifcFormatter() throws Exception {
public void testBindLocalDateWithSpecificFormatter() throws Exception {
JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
registrar.setDateFormatter(org.joda.time.format.DateTimeFormat.forPattern("yyyyMMdd"));
setUp(registrar);
@@ -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,6 +23,8 @@ import javax.management.modelmbean.RequiredModelMBean;
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.modelmbean.ModelMBeanInfoSupport;
import org.junit.Test;
import org.springframework.jmx.AbstractMBeanServerTests;
import org.springframework.jmx.JmxTestBean;
import org.springframework.jmx.export.naming.ObjectNamingStrategy;
@@ -36,6 +38,7 @@ import static org.junit.Assert.*;
*/
public class MBeanExporterOperationsTests extends AbstractMBeanServerTests {
@Test
public void testRegisterManagedResourceWithUserSuppliedObjectName() throws Exception {
ObjectName objectName = ObjectNameManager.getInstance("spring:name=Foo");
@@ -50,6 +53,7 @@ public class MBeanExporterOperationsTests extends AbstractMBeanServerTests {
assertEquals("Incorrect name on MBean", name, bean.getName());
}
@Test
public void testRegisterExistingMBeanWithUserSuppliedObjectName() throws Exception {
ObjectName objectName = ObjectNameManager.getInstance("spring:name=Foo");
ModelMBeanInfo info = new ModelMBeanInfoSupport("myClass", "myDescription", null, null, null, null);
@@ -63,6 +67,7 @@ public class MBeanExporterOperationsTests extends AbstractMBeanServerTests {
assertEquals(info, infoFromServer);
}
@Test
public void testRegisterManagedResourceWithGeneratedObjectName() throws Exception {
final ObjectName objectNameTemplate = ObjectNameManager.getInstance("spring:type=Test");
@@ -88,6 +93,7 @@ public class MBeanExporterOperationsTests extends AbstractMBeanServerTests {
assertObjectNameMatchesTemplate(objectNameTemplate, reg2);
}
@Test
public void testRegisterManagedResourceWithGeneratedObjectNameWithoutUniqueness() throws Exception {
final ObjectName objectNameTemplate = ObjectNameManager.getInstance("spring:type=Test");
@@ -16,26 +16,26 @@
package org.springframework.ui;
import static org.junit.Assert.*;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import static org.junit.Assert.*;
/**
* @author Rick Evans
* @author Juergen Hoeller
@@ -226,12 +226,12 @@ public final class ModelMapTests {
public void testAopCglibProxy() throws Exception {
ModelMap map = new ModelMap();
ProxyFactory factory = new ProxyFactory();
Date date = new Date();
factory.setTarget(date);
SomeInnerClass val = new SomeInnerClass();
factory.setTarget(val);
factory.setProxyTargetClass(true);
map.addAttribute(factory.getProxy());
assertTrue(map.containsKey("date"));
assertEquals(date, map.get("date"));
assertTrue(map.containsKey("someInnerClass"));
assertEquals(val, map.get("someInnerClass"));
}
@Test
@@ -288,11 +288,20 @@ public final class ModelMapTests {
}
private static class SomeInnerClass {
public static class SomeInnerClass {
public boolean equals(Object obj) {
return (obj instanceof SomeInnerClass);
}
@Override
public int hashCode() {
return SomeInnerClass.class.hashCode();
}
}
private static class UKInnerClass {
public static class UKInnerClass {
}
}
@@ -56,6 +56,7 @@ import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.format.Formatter;
import org.springframework.format.number.NumberFormatter;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
@@ -614,8 +615,8 @@ public class DataBinderTests extends TestCase {
assertNull(rod.getSomeMap().get("key4"));
String[] disallowedFields = binder.getBindingResult().getSuppressedFields();
assertEquals(2, disallowedFields.length);
assertEquals("someMap[key3]", disallowedFields[0]);
assertEquals("someMap[key4]", disallowedFields[1]);
assertTrue(ObjectUtils.containsElement(disallowedFields, "someMap[key3]"));
assertTrue(ObjectUtils.containsElement(disallowedFields, "someMap[key4]"));
}
/**
@@ -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,6 +19,7 @@ package org.springframework.core;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.MalformedParameterizedTypeException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
@@ -446,8 +447,13 @@ public abstract class GenericCollectionTypeResolver {
return null;
}
if (clazz.getSuperclass() != null && isIntrospectionCandidate(clazz.getSuperclass())) {
return extractType(clazz.getGenericSuperclass(), source, typeIndex, typeVariableMap, typeIndexesPerLevel,
nestingLevel, currentLevel);
try {
return extractType(clazz.getGenericSuperclass(), source, typeIndex, typeVariableMap,
typeIndexesPerLevel, nestingLevel, currentLevel);
}
catch (MalformedParameterizedTypeException ex) {
// from getGenericSuperclass() - ignore and continue with interface introspection
}
}
Type[] ifcs = clazz.getGenericInterfaces();
if (ifcs != null) {
@@ -18,6 +18,7 @@ package org.springframework.core;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.MalformedParameterizedTypeException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
@@ -74,12 +75,12 @@ public abstract class GenericTypeResolver {
* @param clazz the class to resolve type variables against
* @return the corresponding generic parameter or return type
*/
public static Class<?> resolveParameterType(MethodParameter methodParam, Class clazz) {
public static Class<?> resolveParameterType(MethodParameter methodParam, Class<?> clazz) {
Type genericType = getTargetType(methodParam);
Assert.notNull(clazz, "Class must not be null");
Map<TypeVariable, Type> typeVariableMap = getTypeVariableMap(clazz);
Type rawType = getRawType(genericType, typeVariableMap);
Class result = (rawType instanceof Class ? (Class) rawType : methodParam.getParameterType());
Class<?> result = (rawType instanceof Class ? (Class) rawType : methodParam.getParameterType());
methodParam.setParameterType(result);
methodParam.typeVariableMap = typeVariableMap;
return result;
@@ -227,7 +228,7 @@ public abstract class GenericTypeResolver {
* @param genericIfc the generic interface or superclass to resolve the type argument from
* @return the resolved type of the argument, or {@code null} if not resolvable
*/
public static Class<?> resolveTypeArgument(Class clazz, Class genericIfc) {
public static Class<?> resolveTypeArgument(Class<?> clazz, Class<?> genericIfc) {
Class[] typeArgs = resolveTypeArguments(clazz, genericIfc);
if (typeArgs == null) {
return null;
@@ -248,11 +249,11 @@ public abstract class GenericTypeResolver {
* @return the resolved type of each argument, with the array size matching the
* number of actual type arguments, or {@code null} if not resolvable
*/
public static Class[] resolveTypeArguments(Class clazz, Class genericIfc) {
public static Class[] resolveTypeArguments(Class<?> clazz, Class<?> genericIfc) {
return doResolveTypeArguments(clazz, clazz, genericIfc);
}
private static Class[] doResolveTypeArguments(Class ownerClass, Class classToIntrospect, Class genericIfc) {
private static Class[] doResolveTypeArguments(Class<?> ownerClass, Class<?> classToIntrospect, Class<?> genericIfc) {
while (classToIntrospect != null) {
if (genericIfc.isInterface()) {
Type[] ifcs = classToIntrospect.getGenericInterfaces();
@@ -264,10 +265,15 @@ public abstract class GenericTypeResolver {
}
}
else {
Class[] result = doResolveTypeArguments(
ownerClass, classToIntrospect.getGenericSuperclass(), genericIfc);
if (result != null) {
return result;
try {
Class[] result = doResolveTypeArguments(ownerClass, classToIntrospect.getGenericSuperclass(), genericIfc);
if (result != null) {
return result;
}
}
catch (MalformedParameterizedTypeException ex) {
// from getGenericSuperclass() - return null to skip further superclass traversal
return null;
}
}
classToIntrospect = classToIntrospect.getSuperclass();
@@ -275,7 +281,7 @@ public abstract class GenericTypeResolver {
return null;
}
private static Class[] doResolveTypeArguments(Class ownerClass, Type ifc, Class genericIfc) {
private static Class[] doResolveTypeArguments(Class<?> ownerClass, Type ifc, Class<?> genericIfc) {
if (ifc instanceof ParameterizedType) {
ParameterizedType paramIfc = (ParameterizedType) ifc;
Type rawType = paramIfc.getRawType();
@@ -301,7 +307,7 @@ public abstract class GenericTypeResolver {
/**
* Extract a class instance from given Type.
*/
private static Class extractClass(Class ownerClass, Type arg) {
private static Class<?> extractClass(Class<?> ownerClass, Type arg) {
if (arg instanceof ParameterizedType) {
return extractClass(ownerClass, ((ParameterizedType) arg).getRawType());
}
@@ -368,7 +374,7 @@ public abstract class GenericTypeResolver {
* {@link Class concrete classes} for the specified {@link Class}. Searches
* all super types, enclosing types and interfaces.
*/
public static Map<TypeVariable, Type> getTypeVariableMap(Class clazz) {
public static Map<TypeVariable, Type> getTypeVariableMap(Class<?> clazz) {
Map<TypeVariable, Type> typeVariableMap = typeVariableCache.get(clazz);
if (typeVariableMap == null) {
@@ -377,28 +383,37 @@ public abstract class GenericTypeResolver {
// interfaces
extractTypeVariablesFromGenericInterfaces(clazz.getGenericInterfaces(), typeVariableMap);
// super class
Type genericType = clazz.getGenericSuperclass();
Class type = clazz.getSuperclass();
while (type != null && !Object.class.equals(type)) {
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
populateTypeMapFromParameterizedType(pt, typeVariableMap);
try {
// super class
Class<?> type = clazz;
while (type.getSuperclass() != null && !Object.class.equals(type.getSuperclass())) {
Type genericType = type.getGenericSuperclass();
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
populateTypeMapFromParameterizedType(pt, typeVariableMap);
}
extractTypeVariablesFromGenericInterfaces(type.getSuperclass().getGenericInterfaces(), typeVariableMap);
type = type.getSuperclass();
}
extractTypeVariablesFromGenericInterfaces(type.getGenericInterfaces(), typeVariableMap);
genericType = type.getGenericSuperclass();
type = type.getSuperclass();
}
catch (MalformedParameterizedTypeException ex) {
// from getGenericSuperclass() - ignore and continue with member class check
}
// enclosing class
type = clazz;
while (type.isMemberClass()) {
genericType = type.getGenericSuperclass();
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
populateTypeMapFromParameterizedType(pt, typeVariableMap);
try {
// enclosing class
Class<?> type = clazz;
while (type.isMemberClass()) {
Type genericType = type.getGenericSuperclass();
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
populateTypeMapFromParameterizedType(pt, typeVariableMap);
}
type = type.getEnclosingClass();
}
type = type.getEnclosingClass();
}
catch (MalformedParameterizedTypeException ex) {
// from getGenericSuperclass() - ignore and preserve previously accumulated type variables
}
typeVariableCache.put(clazz, typeVariableMap);
@@ -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.
@@ -54,6 +54,11 @@ public abstract class JdkVersion {
*/
public static final int JAVA_17 = 4;
/**
* Constant identifying the 1.8 JVM (Java 8).
*/
public static final int JAVA_18 = 5;
private static final String javaVersion;
@@ -62,7 +67,10 @@ public abstract class JdkVersion {
static {
javaVersion = System.getProperty("java.version");
// version String should look like "1.4.2_10"
if (javaVersion.contains("1.7.")) {
if (javaVersion.contains("1.8.")) {
majorJavaVersion = JAVA_18;
}
else if (javaVersion.contains("1.7.")) {
majorJavaVersion = JAVA_17;
}
else if (javaVersion.contains("1.6.")) {
@@ -87,7 +95,7 @@ public abstract class JdkVersion {
/**
* Get the major version code. This means we can do things like
* {@code if (getMajorJavaVersion() < JAVA_14)}.
* {@code if (getMajorJavaVersion() >= JAVA_17)}.
* @return a code comparable to the JAVA_XX codes in this class
* @see #JAVA_13
* @see #JAVA_14
@@ -114,8 +114,15 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Exception thrown while reading '.class' file for class [" + clazz
+ "] - unable to determine constructors/methods parameter names", ex);
logger.debug("Exception thrown while reading '.class' file for class [" + clazz +
"] - unable to determine constructors/methods parameter names", ex);
}
}
catch (IllegalArgumentException ex) {
if (logger.isDebugEnabled()) {
logger.debug("ASM ClassReader failed to parse class file [" + clazz +
"], probably due to a new Java class file version that isn't supported yet " +
"- unable to determine constructors/methods parameter names", ex);
}
}
finally {
@@ -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.
@@ -24,7 +24,7 @@ import org.springframework.util.Assert;
/**
* The purpose of this class is to enable capturing and passing a generic
* {@link Type}. In order to capture the generic type and retain it at runtime,
* you need to create a sub-class as follows:
* you need to create a subclass as follows:
*
* <pre class="code">
* ParameterizedTypeReference&lt;List&lt;String&gt;&gt; typeRef = new ParameterizedTypeReference&lt;List&lt;String&gt;&gt;() {};
@@ -37,54 +37,31 @@ import org.springframework.util.Assert;
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @since 3.2
*
* @see <a href="http://gafter.blogspot.nl/2006/12/super-type-tokens.html">Neal Gafter on Super Type Tokens</a>
*/
public abstract class ParameterizedTypeReference<T> {
private final Type type;
protected ParameterizedTypeReference() {
Class<?> parameterizedTypeReferenceSubClass = findParameterizedTypeReferenceSubClass(getClass());
Type type = parameterizedTypeReferenceSubClass.getGenericSuperclass();
Class<?> parameterizedTypeReferenceSubclass = findParameterizedTypeReferenceSubclass(getClass());
Type type = parameterizedTypeReferenceSubclass.getGenericSuperclass();
Assert.isInstanceOf(ParameterizedType.class, type);
ParameterizedType parameterizedType = (ParameterizedType) type;
Assert.isTrue(parameterizedType.getActualTypeArguments().length == 1);
this.type = parameterizedType.getActualTypeArguments()[0];
}
private static Class<?> findParameterizedTypeReferenceSubClass(Class<?> child) {
Class<?> parent = child.getSuperclass();
if (Object.class.equals(parent)) {
throw new IllegalStateException("Expected ParameterizedTypeReference superclass");
}
else if (ParameterizedTypeReference.class.equals(parent)) {
return child;
}
else {
return findParameterizedTypeReferenceSubClass(parent);
}
}
public Type getType() {
return this.type;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o instanceof ParameterizedTypeReference) {
ParameterizedTypeReference<?> other = (ParameterizedTypeReference<?>) o;
return this.type.equals(other.type);
}
return false;
public boolean equals(Object obj) {
return (this == obj || (obj instanceof ParameterizedTypeReference &&
this.type.equals(((ParameterizedTypeReference) obj).type)));
}
@Override
@@ -96,4 +73,19 @@ public abstract class ParameterizedTypeReference<T> {
public String toString() {
return "ParameterizedTypeReference<" + this.type + ">";
}
private static Class<?> findParameterizedTypeReferenceSubclass(Class<?> child) {
Class<?> parent = child.getSuperclass();
if (Object.class.equals(parent)) {
throw new IllegalStateException("Expected ParameterizedTypeReference superclass");
}
else if (ParameterizedTypeReference.class.equals(parent)) {
return child;
}
else {
return findParameterizedTypeReferenceSubclass(parent);
}
}
}
@@ -51,7 +51,7 @@ public class AnnotationAwareOrderComparator extends OrderComparator {
}
if (obj != null) {
Class<?> clazz = (obj instanceof Class ? (Class) obj : obj.getClass());
Order order = clazz.getAnnotation(Order.class);
Order order = AnnotationUtils.findAnnotation(clazz, Order.class);
if (order != null) {
return order.value();
}
@@ -19,7 +19,6 @@ package org.springframework.core.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
@@ -121,24 +120,24 @@ public abstract class AnnotationUtils {
*/
public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) {
A annotation = getAnnotation(method, annotationType);
Class<?> cl = method.getDeclaringClass();
Class<?> clazz = method.getDeclaringClass();
if (annotation == null) {
annotation = searchOnInterfaces(method, annotationType, cl.getInterfaces());
annotation = searchOnInterfaces(method, annotationType, clazz.getInterfaces());
}
while (annotation == null) {
cl = cl.getSuperclass();
if (cl == null || cl == Object.class) {
clazz = clazz.getSuperclass();
if (clazz == null || clazz.equals(Object.class)) {
break;
}
try {
Method equivalentMethod = cl.getDeclaredMethod(method.getName(), method.getParameterTypes());
Method equivalentMethod = clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
annotation = getAnnotation(equivalentMethod, annotationType);
}
catch (NoSuchMethodException ex) {
// No equivalent method found
}
if (annotation == null) {
annotation = searchOnInterfaces(method, annotationType, cl.getInterfaces());
annotation = searchOnInterfaces(method, annotationType, clazz.getInterfaces());
}
}
return annotation;
@@ -217,7 +216,7 @@ public abstract class AnnotationUtils {
}
}
Class<?> superClass = clazz.getSuperclass();
if (superClass == null || superClass == Object.class) {
if (superClass == null || superClass.equals(Object.class)) {
return null;
}
return findAnnotation(superClass, annotationType);
@@ -273,25 +272,22 @@ public abstract class AnnotationUtils {
* @return the first {@link Class} in the inheritance hierarchy of the specified
* {@code clazz} which declares an annotation of at least one of the specified
* {@code annotationTypes}, or {@code null} if not found
* @since 3.2.2
* @see Class#isAnnotationPresent(Class)
* @see Class#getDeclaredAnnotations()
* @see #findAnnotationDeclaringClass(Class, Class)
* @see #isAnnotationDeclaredLocally(Class, Class)
* @since 3.2.2
*/
public static Class<?> findAnnotationDeclaringClassForTypes(List<Class<? extends Annotation>> annotationTypes,
Class<?> clazz) {
public static Class<?> findAnnotationDeclaringClassForTypes(List<Class<? extends Annotation>> annotationTypes, Class<?> clazz) {
Assert.notEmpty(annotationTypes, "The list of annotation types must not be empty");
if (clazz == null || clazz.equals(Object.class)) {
return null;
}
for (Class<? extends Annotation> annotationType : annotationTypes) {
if (isAnnotationDeclaredLocally(annotationType, clazz)) {
return clazz;
}
}
return findAnnotationDeclaringClassForTypes(annotationTypes, clazz.getSuperclass());
}
@@ -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.
@@ -437,7 +437,7 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
public <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
return this.propertyResolver.getProperty(key, targetType, defaultValue);
};
}
public <T> Class<T> getPropertyAsClass(String key, Class<T> targetType) {
return this.propertyResolver.getPropertyAsClass(key, targetType);
@@ -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.
@@ -16,8 +16,6 @@
package org.springframework.core.env;
import static java.lang.String.format;
import org.springframework.core.convert.ConversionException;
import org.springframework.util.ClassUtils;
@@ -35,6 +33,7 @@ public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
private final PropertySources propertySources;
/**
* Create a new resolver against the given property sources.
* @param propertySources the set of {@link PropertySource} objects to use
@@ -43,106 +42,110 @@ public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
this.propertySources = propertySources;
}
@Override
public boolean containsProperty(String key) {
for (PropertySource<?> propertySource : this.propertySources) {
if (propertySource.containsProperty(key)) {
return true;
if (this.propertySources != null) {
for (PropertySource<?> propertySource : this.propertySources) {
if (propertySource.containsProperty(key)) {
return true;
}
}
}
return false;
}
@Override
public String getProperty(String key) {
if (logger.isTraceEnabled()) {
logger.trace(format("getProperty(\"%s\") (implicit targetType [String])", key));
}
return this.getProperty(key, String.class);
return getProperty(key, String.class);
}
@Override
public <T> T getProperty(String key, Class<T> targetValueType) {
boolean debugEnabled = logger.isDebugEnabled();
if (logger.isTraceEnabled()) {
logger.trace(format("getProperty(\"%s\", %s)", key, targetValueType.getSimpleName()));
logger.trace(String.format("getProperty(\"%s\", %s)", key, targetValueType.getSimpleName()));
}
for (PropertySource<?> propertySource : this.propertySources) {
if (debugEnabled) {
logger.debug(format("Searching for key '%s' in [%s]", key, propertySource.getName()));
}
Object value;
if ((value = propertySource.getProperty(key)) != null) {
Class<?> valueType = value.getClass();
if (String.class.equals(valueType)) {
value = this.resolveNestedPlaceholders((String) value);
}
if (this.propertySources != null) {
for (PropertySource<?> propertySource : this.propertySources) {
if (debugEnabled) {
logger.debug(
format("Found key '%s' in [%s] with type [%s] and value '%s'",
key, propertySource.getName(), valueType.getSimpleName(), value));
logger.debug(String.format("Searching for key '%s' in [%s]", key, propertySource.getName()));
}
if (!this.conversionService.canConvert(valueType, targetValueType)) {
throw new IllegalArgumentException(
format("Cannot convert value [%s] from source type [%s] to target type [%s]",
value, valueType.getSimpleName(), targetValueType.getSimpleName()));
Object value;
if ((value = propertySource.getProperty(key)) != null) {
Class<?> valueType = value.getClass();
if (String.class.equals(valueType)) {
value = this.resolveNestedPlaceholders((String) value);
}
if (debugEnabled) {
logger.debug(String.format("Found key '%s' in [%s] with type [%s] and value '%s'",
key, propertySource.getName(), valueType.getSimpleName(), value));
}
if (!this.conversionService.canConvert(valueType, targetValueType)) {
throw new IllegalArgumentException(String.format(
"Cannot convert value [%s] from source type [%s] to target type [%s]",
value, valueType.getSimpleName(), targetValueType.getSimpleName()));
}
return conversionService.convert(value, targetValueType);
}
return conversionService.convert(value, targetValueType);
}
}
if (debugEnabled) {
logger.debug(format("Could not find key '%s' in any property source. Returning [null]", key));
logger.debug(String.format("Could not find key '%s' in any property source. Returning [null]", key));
}
return null;
}
@Override
public <T> Class<T> getPropertyAsClass(String key, Class<T> targetValueType) {
boolean debugEnabled = logger.isDebugEnabled();
if (logger.isTraceEnabled()) {
logger.trace(format("getPropertyAsClass(\"%s\", %s)", key, targetValueType.getSimpleName()));
logger.trace(String.format("getPropertyAsClass(\"%s\", %s)", key, targetValueType.getSimpleName()));
}
for (PropertySource<?> propertySource : this.propertySources) {
if (debugEnabled) {
logger.debug(format("Searching for key '%s' in [%s]", key, propertySource.getName()));
}
Object value;
if ((value = propertySource.getProperty(key)) != null) {
if (this.propertySources != null) {
for (PropertySource<?> propertySource : this.propertySources) {
if (debugEnabled) {
logger.debug(
format("Found key '%s' in [%s] with value '%s'", key, propertySource.getName(), value));
logger.debug(String.format("Searching for key '%s' in [%s]", key, propertySource.getName()));
}
Class<?> clazz;
if (value instanceof String) {
try {
clazz = ClassUtils.forName((String)value, null);
} catch (Exception ex) {
throw new ClassConversionException((String)value, targetValueType, ex);
Object value = propertySource.getProperty(key);
if (value != null) {
if (debugEnabled) {
logger.debug(String.format("Found key '%s' in [%s] with value '%s'", key, propertySource.getName(), value));
}
Class<?> clazz;
if (value instanceof String) {
try {
clazz = ClassUtils.forName((String)value, null);
}
catch (Exception ex) {
throw new ClassConversionException((String)value, targetValueType, ex);
}
}
else if (value instanceof Class) {
clazz = (Class<?>)value;
}
else {
clazz = value.getClass();
}
if (!targetValueType.isAssignableFrom(clazz)) {
throw new ClassConversionException(clazz, targetValueType);
}
@SuppressWarnings("unchecked")
Class<T> targetClass = (Class<T>) clazz;
return targetClass;
}
else if (value instanceof Class) {
clazz = (Class<?>)value;
} else {
clazz = value.getClass();
}
if (!targetValueType.isAssignableFrom(clazz)) {
throw new ClassConversionException(clazz, targetValueType);
}
@SuppressWarnings("unchecked")
Class<T> targetClass = (Class<T>)clazz;
return targetClass;
}
}
if (debugEnabled) {
logger.debug(format("Could not find key '%s' in any property source. Returning [null]", key));
logger.debug(String.format("Could not find key '%s' in any property source. Returning [null]", key));
}
return null;
}
@SuppressWarnings("serial")
static class ClassConversionException extends ConversionException {
private static class ClassConversionException extends ConversionException {
public ClassConversionException(Class<?> actual, Class<?> expected) {
super(String.format("Actual type %s is not assignable to expected type %s", actual.getName(), expected.getName()));
}
@@ -151,4 +154,5 @@ public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
super(String.format("Could not find/load class %s during attempt to convert to %s", actual, expected.getName()), ex);
}
}
}
@@ -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,12 +19,11 @@ package org.springframework.core.io;
import java.beans.PropertyEditorSupport;
import java.io.IOException;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.env.PropertyResolver;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* {@link java.beans.PropertyEditor Editor} for {@link Resource}
* descriptors, to automatically convert {@code String} locations
@@ -51,7 +50,7 @@ public class ResourceEditor extends PropertyEditorSupport {
private final ResourceLoader resourceLoader;
private final PropertyResolver propertyResolver;
private PropertyResolver propertyResolver;
private final boolean ignoreUnresolvablePlaceholders;
@@ -61,7 +60,7 @@ public class ResourceEditor extends PropertyEditorSupport {
* using a {@link DefaultResourceLoader} and {@link StandardEnvironment}.
*/
public ResourceEditor() {
this(new DefaultResourceLoader(), new StandardEnvironment());
this(new DefaultResourceLoader(), null);
}
/**
@@ -73,7 +72,21 @@ public class ResourceEditor extends PropertyEditorSupport {
*/
@Deprecated
public ResourceEditor(ResourceLoader resourceLoader) {
this(resourceLoader, new StandardEnvironment(), true);
this(resourceLoader, null, true);
}
/**
* Create a new instance of the {@link ResourceEditor} class
* using the given {@link ResourceLoader}.
* @param resourceLoader the {@code ResourceLoader} to use
* @param ignoreUnresolvablePlaceholders whether to ignore unresolvable placeholders
* if no corresponding property could be found
* @deprecated as of Spring 3.1 in favor of
* {@link #ResourceEditor(ResourceLoader, PropertyResolver, boolean)}
*/
@Deprecated
public ResourceEditor(ResourceLoader resourceLoader, boolean ignoreUnresolvablePlaceholders) {
this(resourceLoader, null, ignoreUnresolvablePlaceholders);
}
/**
@@ -86,20 +99,6 @@ public class ResourceEditor extends PropertyEditorSupport {
this(resourceLoader, propertyResolver, true);
}
/**
* Create a new instance of the {@link ResourceEditor} class
* using the given {@link ResourceLoader}.
* @param resourceLoader the {@code ResourceLoader} to use
* @param ignoreUnresolvablePlaceholders whether to ignore unresolvable placeholders
* if no corresponding property could be found
* @deprecated as of Spring 3.1 in favor of
* {@link #ResourceEditor(ResourceLoader, PropertyResolver, boolean)}
*/
@Deprecated
public ResourceEditor(ResourceLoader resourceLoader, boolean ignoreUnresolvablePlaceholders) {
this(resourceLoader, new StandardEnvironment(), ignoreUnresolvablePlaceholders);
}
/**
* Create a new instance of the {@link ResourceEditor} class
* using the given {@link ResourceLoader}.
@@ -110,7 +109,6 @@ public class ResourceEditor extends PropertyEditorSupport {
*/
public ResourceEditor(ResourceLoader resourceLoader, PropertyResolver propertyResolver, boolean ignoreUnresolvablePlaceholders) {
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
Assert.notNull(propertyResolver, "PropertyResolver must not be null");
this.resourceLoader = resourceLoader;
this.propertyResolver = propertyResolver;
this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
@@ -137,9 +135,11 @@ public class ResourceEditor extends PropertyEditorSupport {
* @see PropertyResolver#resolveRequiredPlaceholders
*/
protected String resolvePath(String path) {
return this.ignoreUnresolvablePlaceholders ?
this.propertyResolver.resolvePlaceholders(path) :
this.propertyResolver.resolveRequiredPlaceholders(path);
if (this.propertyResolver == null) {
this.propertyResolver = new StandardEnvironment();
}
return (this.ignoreUnresolvablePlaceholders ? this.propertyResolver.resolvePlaceholders(path) :
this.propertyResolver.resolveRequiredPlaceholders(path));
}
@@ -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 java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
@@ -40,6 +41,11 @@ import org.springframework.util.StringUtils;
*/
public class UrlResource extends AbstractFileResolvingResource {
/**
* Original URI, if available; used for URI and File access.
*/
private final URI uri;
/**
* Original URL, used for actual access.
*/
@@ -50,14 +56,21 @@ public class UrlResource extends AbstractFileResolvingResource {
*/
private final URL cleanedUrl;
/**
* Original URI, if available; used for URI and File access.
* Create a new UrlResource based on the given URI object.
* @param uri a URI
* @throws MalformedURLException if the given URL path is not valid
*/
private final URI uri;
public UrlResource(URI uri) throws MalformedURLException {
Assert.notNull(uri, "URI must not be null");
this.uri = uri;
this.url = uri.toURL();
this.cleanedUrl = getCleanedUrl(this.url, uri.toString());
}
/**
* Create a new UrlResource.
* Create a new UrlResource based on the given URL object.
* @param url a URL
*/
public UrlResource(URL url) {
@@ -68,27 +81,56 @@ public class UrlResource extends AbstractFileResolvingResource {
}
/**
* Create a new UrlResource.
* @param uri a URI
* @throws MalformedURLException if the given URL path is not valid
*/
public UrlResource(URI uri) throws MalformedURLException {
Assert.notNull(uri, "URI must not be null");
this.url = uri.toURL();
this.cleanedUrl = getCleanedUrl(this.url, uri.toString());
this.uri = uri;
}
/**
* Create a new UrlResource.
* Create a new UrlResource based on a URL path.
* <p>Note: The given path needs to be pre-encoded if necessary.
* @param path a URL path
* @throws MalformedURLException if the given URL path is not valid
* @see java.net.URL#URL(String)
*/
public UrlResource(String path) throws MalformedURLException {
Assert.notNull(path, "Path must not be null");
this.uri = null;
this.url = new URL(path);
this.cleanedUrl = getCleanedUrl(this.url, path);
this.uri = null;
}
/**
* Create a new UrlResource based on a URI specification.
* <p>The given parts will automatically get encoded if necessary.
* @param protocol the URL protocol to use (e.g. "jar" or "file" - without colon);
* also known as "scheme"
* @param location the location (e.g. the file path within that protocol);
* also known as "scheme-specific part"
* @throws MalformedURLException if the given URL specification is not valid
* @see java.net.URI#URI(String, String, String)
*/
public UrlResource(String protocol, String location) throws MalformedURLException {
this(protocol, location, null);
}
/**
* Create a new UrlResource based on a URI specification.
* <p>The given parts will automatically get encoded if necessary.
* @param protocol the URL protocol to use (e.g. "jar" or "file" - without colon);
* also known as "scheme"
* @param location the location (e.g. the file path within that protocol);
* also known as "scheme-specific part"
* @param fragment the fragment within that location (e.g. anchor on an HTML page,
* as following after a "#" separator)
* @throws MalformedURLException if the given URL specification is not valid
* @see java.net.URI#URI(String, String, String)
*/
public UrlResource(String protocol, String location, String fragment) throws MalformedURLException {
try {
this.uri = new URI(protocol, location, fragment);
this.url = this.uri.toURL();
this.cleanedUrl = getCleanedUrl(this.url, this.uri.toString());
}
catch (URISyntaxException ex) {
MalformedURLException exToThrow = new MalformedURLException(ex.getMessage());
exToThrow.initCause(ex);
throw exToThrow;
}
}
/**
@@ -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,10 +25,12 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
/**
* Editor for {@link org.springframework.core.io.Resource} arrays, to
@@ -55,10 +57,10 @@ public class ResourceArrayPropertyEditor extends PropertyEditorSupport {
private static final Log logger = LogFactory.getLog(ResourceArrayPropertyEditor.class);
private final PropertyResolver propertyResolver;
private final ResourcePatternResolver resourcePatternResolver;
private PropertyResolver propertyResolver;
private final boolean ignoreUnresolvablePlaceholders;
@@ -69,7 +71,7 @@ public class ResourceArrayPropertyEditor extends PropertyEditorSupport {
* @see Environment
*/
public ResourceArrayPropertyEditor() {
this(new PathMatchingResourcePatternResolver(), new StandardEnvironment(), true);
this(new PathMatchingResourcePatternResolver(), null, true);
}
/**
@@ -80,7 +82,20 @@ public class ResourceArrayPropertyEditor extends PropertyEditorSupport {
*/
@Deprecated
public ResourceArrayPropertyEditor(ResourcePatternResolver resourcePatternResolver) {
this(resourcePatternResolver, new StandardEnvironment(), true);
this(resourcePatternResolver, null, true);
}
/**
* Create a new ResourceArrayPropertyEditor with the given {@link ResourcePatternResolver}
* and a {@link StandardEnvironment}.
* @param resourcePatternResolver the ResourcePatternResolver to use
* @param ignoreUnresolvablePlaceholders whether to ignore unresolvable placeholders
* if no corresponding system property could be found
* @deprecated as of 3.1 in favor of {@link #ResourceArrayPropertyEditor(ResourcePatternResolver, PropertyResolver, boolean)}
*/
@Deprecated
public ResourceArrayPropertyEditor(ResourcePatternResolver resourcePatternResolver, boolean ignoreUnresolvablePlaceholders) {
this(resourcePatternResolver, null, ignoreUnresolvablePlaceholders);
}
/**
@@ -93,19 +108,6 @@ public class ResourceArrayPropertyEditor extends PropertyEditorSupport {
this(resourcePatternResolver, propertyResolver, true);
}
/**
* Create a new ResourceArrayPropertyEditor with the given {@link ResourcePatternResolver}
* and a {@link StandardEnvironment}.
* @param resourcePatternResolver the ResourcePatternResolver to use
* @param ignoreUnresolvablePlaceholders whether to ignore unresolvable placeholders
* if no corresponding system property could be found
* @deprecated as of 3.1 in favor of {@link #ResourceArrayPropertyEditor(ResourcePatternResolver, PropertyResolver, boolean)}
*/
@Deprecated
public ResourceArrayPropertyEditor(ResourcePatternResolver resourcePatternResolver, boolean ignoreUnresolvablePlaceholders) {
this(resourcePatternResolver, new StandardEnvironment(), ignoreUnresolvablePlaceholders);
}
/**
* Create a new ResourceArrayPropertyEditor with the given {@link ResourcePatternResolver}
* and {@link PropertyResolver} (typically an {@link Environment}).
@@ -116,6 +118,8 @@ public class ResourceArrayPropertyEditor extends PropertyEditorSupport {
*/
public ResourceArrayPropertyEditor(ResourcePatternResolver resourcePatternResolver,
PropertyResolver propertyResolver, boolean ignoreUnresolvablePlaceholders) {
Assert.notNull(resourcePatternResolver, "ResourcePatternResolver must not be null");
this.resourcePatternResolver = resourcePatternResolver;
this.propertyResolver = propertyResolver;
this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
@@ -197,9 +201,11 @@ public class ResourceArrayPropertyEditor extends PropertyEditorSupport {
* @see PropertyResolver#resolveRequiredPlaceholders(String)
*/
protected String resolvePath(String path) {
return this.ignoreUnresolvablePlaceholders ?
this.propertyResolver.resolvePlaceholders(path) :
this.propertyResolver.resolveRequiredPlaceholders(path);
if (this.propertyResolver == null) {
this.propertyResolver = new StandardEnvironment();
}
return (this.ignoreUnresolvablePlaceholders ? this.propertyResolver.resolvePlaceholders(path) :
this.propertyResolver.resolveRequiredPlaceholders(path));
}
}
@@ -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.
@@ -145,6 +145,8 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
return AnnotationUtils.getAnnotationAttributes(
ann, classValuesAsString, this.nestedAnnotationsAsMap);
}
}
for (Annotation ann : anns) {
for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
if (metaAnn.annotationType().getName().equals(annotationType)) {
return AnnotationUtils.getAnnotationAttributes(
@@ -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.
@@ -28,6 +28,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.SpringAsmInfo;
import org.springframework.asm.Type;
@@ -50,14 +51,12 @@ abstract class AbstractRecursiveAnnotationVisitor extends AnnotationVisitor {
protected final ClassLoader classLoader;
public AbstractRecursiveAnnotationVisitor(ClassLoader classLoader, AnnotationAttributes attributes) {
super(SpringAsmInfo.ASM_VERSION);
this.classLoader = classLoader;
this.attributes = attributes;
}
public void visit(String attributeName, Object attributeValue) {
this.attributes.put(attributeName, attributeValue);
}
@@ -74,6 +73,11 @@ abstract class AbstractRecursiveAnnotationVisitor extends AnnotationVisitor {
}
public void visitEnum(String attributeName, String asmTypeDescriptor, String attributeValue) {
Object newValue = getEnumValue(asmTypeDescriptor, attributeValue);
visit(attributeName, newValue);
}
protected Object getEnumValue(String asmTypeDescriptor, String attributeValue) {
Object valueToUse = attributeValue;
try {
Class<?> enumType = this.classLoader.loadClass(Type.getType(asmTypeDescriptor).getClassName());
@@ -88,7 +92,7 @@ abstract class AbstractRecursiveAnnotationVisitor extends AnnotationVisitor {
catch (IllegalAccessException ex) {
this.logger.warn("Could not access enum value while reading annotation metadata", ex);
}
this.attributes.put(attributeName, valueToUse);
return valueToUse;
}
}
@@ -104,7 +108,6 @@ final class RecursiveAnnotationArrayVisitor extends AbstractRecursiveAnnotationV
private final List<AnnotationAttributes> allNestedAttributes = new ArrayList<AnnotationAttributes>();
public RecursiveAnnotationArrayVisitor(
String attributeName, AnnotationAttributes attributes, ClassLoader classLoader) {
super(classLoader, attributes);
@@ -152,14 +155,12 @@ class RecursiveAnnotationAttributesVisitor extends AbstractRecursiveAnnotationVi
private final String annotationType;
public RecursiveAnnotationAttributesVisitor(
String annotationType, AnnotationAttributes attributes, ClassLoader classLoader) {
super(classLoader, attributes);
this.annotationType = annotationType;
}
public final void visitEnd() {
try {
Class<?> annotationClass = this.classLoader.loadClass(this.annotationType);
@@ -223,7 +224,6 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib
private final Map<String, Set<String>> metaAnnotationMap;
public AnnotationAttributesReadingVisitor(
String annotationType, Map<String, AnnotationAttributes> attributesMap,
Map<String, Set<String>> metaAnnotationMap, ClassLoader classLoader) {
@@ -258,4 +258,5 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib
this.metaAnnotationMap.put(annotationClass.getName(), metaAnnotationTypeNames);
}
}
}
@@ -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.
@@ -105,19 +105,11 @@ final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor
}
public AnnotationAttributes getAnnotationAttributes(String annotationType, boolean classValuesAsString) {
return getAnnotationAttributes(annotationType, classValuesAsString, false);
}
public AnnotationAttributes getAnnotationAttributes(
String annotationType, boolean classValuesAsString, boolean nestedAttributesAsMap) {
AnnotationAttributes raw = this.attributeMap.get(annotationType);
return convertClassValues(raw, classValuesAsString, nestedAttributesAsMap);
return convertClassValues(raw, classValuesAsString);
}
private AnnotationAttributes convertClassValues(
AnnotationAttributes original, boolean classValuesAsString, boolean nestedAttributesAsMap) {
private AnnotationAttributes convertClassValues(AnnotationAttributes original, boolean classValuesAsString) {
if (original == null) {
return null;
}
@@ -126,12 +118,12 @@ final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor
try {
Object value = entry.getValue();
if (value instanceof AnnotationAttributes) {
value = convertClassValues((AnnotationAttributes)value, classValuesAsString, nestedAttributesAsMap);
value = convertClassValues((AnnotationAttributes) value, classValuesAsString);
}
else if (value instanceof AnnotationAttributes[]) {
AnnotationAttributes[] values = (AnnotationAttributes[])value;
for (int i = 0; i < values.length; i++) {
values[i] = convertClassValues(values[i], classValuesAsString, nestedAttributesAsMap);
values[i] = convertClassValues(values[i], classValuesAsString);
}
}
else if (value instanceof Type) {
@@ -182,4 +174,5 @@ final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor
annotatedMethods.addAll(list);
return annotatedMethods;
}
}
@@ -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.
@@ -45,7 +45,7 @@ final class MethodMetadataReadingVisitor extends MethodVisitor implements Method
private final int access;
private String declaringClassName;
private final String declaringClassName;
private final ClassLoader classLoader;
@@ -53,8 +53,10 @@ final class MethodMetadataReadingVisitor extends MethodVisitor implements Method
private final Map<String, AnnotationAttributes> attributeMap = new LinkedHashMap<String, AnnotationAttributes>(2);
public MethodMetadataReadingVisitor(String name, int access, String declaringClassName, ClassLoader classLoader,
MultiValueMap<String, MethodMetadata> methodMetadataMap) {
super(SpringAsmInfo.ASM_VERSION);
this.name = name;
this.access = access;
@@ -63,10 +65,11 @@ final class MethodMetadataReadingVisitor extends MethodVisitor implements Method
this.methodMetadataMap = methodMetadataMap;
}
@Override
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
String className = Type.getType(desc).getClassName();
methodMetadataMap.add(className, this);
this.methodMetadataMap.add(className, this);
return new AnnotationAttributesReadingVisitor(className, this.attributeMap, null, this.classLoader);
}
@@ -97,4 +100,5 @@ final class MethodMetadataReadingVisitor extends MethodVisitor implements Method
public String getDeclaringClassName() {
return this.declaringClassName;
}
}
@@ -64,7 +64,7 @@ final class SimpleMetadataReader implements MetadataReader {
classReader.accept(visitor, ClassReader.SKIP_DEBUG);
this.annotationMetadata = visitor;
// (since AnnotationMetadataReader extends ClassMetadataReadingVisitor)
// (since AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor)
this.classMetadata = visitor;
this.resource = resource;
}
@@ -184,7 +184,7 @@ public abstract class Assert {
*/
public static void doesNotContain(String textToSearch, String substring, String message) {
if (StringUtils.hasLength(textToSearch) && StringUtils.hasLength(substring) &&
textToSearch.indexOf(substring) != -1) {
textToSearch.contains(substring)) {
throw new IllegalArgumentException(message);
}
}
@@ -236,8 +236,8 @@ public abstract class Assert {
*/
public static void noNullElements(Object[] array, String message) {
if (array != null) {
for (int i = 0; i < array.length; i++) {
if (array[i] == null) {
for (Object element : array) {
if (element == null) {
throw new IllegalArgumentException(message);
}
}
@@ -315,7 +315,7 @@ public abstract class Assert {
* @throws IllegalArgumentException if the object is not an instance of clazz
* @see Class#isInstance
*/
public static void isInstanceOf(Class clazz, Object obj) {
public static void isInstanceOf(Class<?> clazz, Object obj) {
isInstanceOf(clazz, obj, "");
}
@@ -331,7 +331,7 @@ public abstract class Assert {
* @throws IllegalArgumentException if the object is not an instance of clazz
* @see Class#isInstance
*/
public static void isInstanceOf(Class type, Object obj, String message) {
public static void isInstanceOf(Class<?> type, Object obj, String message) {
notNull(type, "Type to check against must not be null");
if (!type.isInstance(obj)) {
throw new IllegalArgumentException(
@@ -348,7 +348,7 @@ public abstract class Assert {
* @param subType the sub type to check
* @throws IllegalArgumentException if the classes are not assignable
*/
public static void isAssignable(Class superType, Class subType) {
public static void isAssignable(Class<?> superType, Class<?> subType) {
isAssignable(superType, subType, "");
}
@@ -363,7 +363,7 @@ public abstract class Assert {
* ok when prepended to it.
* @throws IllegalArgumentException if the classes are not assignable
*/
public static void isAssignable(Class superType, Class subType, String message) {
public static void isAssignable(Class<?> superType, Class<?> subType, String message) {
notNull(superType, "Type to check against must not be null");
if (subType == null || !superType.isAssignableFrom(subType)) {
throw new IllegalArgumentException(message + subType + " is not assignable to " + superType);
@@ -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,16 +20,17 @@ import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Test fixture for {@link ParameterizedTypeReference}.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
*/
public class ParameterizedTypeReferenceTest {
public class ParameterizedTypeReferenceTests {
@Test
public void map() throws NoSuchMethodException {
@@ -58,4 +59,5 @@ public class ParameterizedTypeReferenceTest {
public static List<String> listMethod() {
return null;
}
}
@@ -45,6 +45,16 @@ public class AnnotationAwareOrderComparatorTests {
assertTrue(list.get(1) instanceof B);
}
@Test
public void sortInstancesWithSubclass() {
List<Object> list = new ArrayList<>();
list.add(new B());
list.add(new C());
AnnotationAwareOrderComparator.sort(list);
assertTrue(list.get(0) instanceof C);
assertTrue(list.get(1) instanceof B);
}
@Test
public void sortClasses() {
List<Object> list = new ArrayList<>();
@@ -55,6 +65,16 @@ public class AnnotationAwareOrderComparatorTests {
assertEquals(B.class, list.get(1));
}
@Test
public void sortClassesWithSubclass() {
List<Object> list = new ArrayList<>();
list.add(B.class);
list.add(C.class);
AnnotationAwareOrderComparator.sort(list);
assertEquals(C.class, list.get(0));
assertEquals(B.class, list.get(1));
}
@Order(1)
private static class A {
@@ -64,4 +84,7 @@ public class AnnotationAwareOrderComparatorTests {
private static class B {
}
private static class C extends A {
}
}
@@ -0,0 +1,36 @@
/*
* 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.
* 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.tests;
import org.junit.Test;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
* General build related tests. Part of spring-core to ensure that they run early in the
* build process.
*/
public class BuildTests {
@Test
public void javaVersion() throws Exception {
Assume.group(TestGroup.CI);
assertThat("Java Version", JavaVersion.runningVersion(), equalTo(JavaVersion.JAVA_17));
}
}
@@ -54,7 +54,12 @@ public enum TestGroup {
* Tests requiring the presence of jmxremote_optional.jar in jre/lib/ext in order to
* avoid "Unsupported protocol: jmxmp" errors.
*/
JMXMP;
JMXMP,
/**
* Tests that should only be run on the continuous integration server.
*/
CI;
/**
@@ -64,7 +64,7 @@ public class TestGroupTests {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Unable to find test group 'missing' when parsing " +
"testGroups value: 'performance, missing'. Available groups include: " +
"[LONG_RUNNING,PERFORMANCE,JMXMP]");
"[LONG_RUNNING,PERFORMANCE,JMXMP,CI]");
TestGroup.parse("performance, missing");
}
@@ -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.
@@ -47,70 +47,14 @@ public class MethodReference extends SpelNodeImpl {
public MethodReference(boolean nullSafe, String methodName, int pos, SpelNodeImpl... arguments) {
super(pos,arguments);
super(pos, arguments);
this.name = methodName;
this.nullSafe = nullSafe;
}
class MethodValueRef implements ValueRef {
private ExpressionState state;
private EvaluationContext evaluationContext;
private Object target;
private Object[] arguments;
MethodValueRef(ExpressionState state, EvaluationContext evaluationContext, Object object, Object[] arguments) {
this.state = state;
this.evaluationContext = evaluationContext;
this.target = object;
this.arguments = arguments;
}
public TypedValue getValue() {
MethodExecutor executorToUse = cachedExecutor;
if (executorToUse != null) {
try {
return executorToUse.execute(evaluationContext, target, arguments);
}
catch (AccessException ae) {
// Two reasons this can occur:
// 1. the method invoked actually threw a real exception
// 2. the method invoked was not passed the arguments it expected and has become 'stale'
// In the first case we should not retry, in the second case we should see if there is a
// better suited method.
// To determine which situation it is, the AccessException will contain a cause.
// If the cause is an InvocationTargetException, a user exception was thrown inside the method.
// Otherwise the method could not be invoked.
throwSimpleExceptionIfPossible(state, ae);
// at this point we know it wasn't a user problem so worth a retry if a better candidate can be found
cachedExecutor = null;
}
}
// either there was no accessor or it no longer existed
executorToUse = findAccessorForMethod(name, getTypes(arguments), target, evaluationContext);
cachedExecutor = executorToUse;
try {
return executorToUse.execute(evaluationContext, target, arguments);
} catch (AccessException ae) {
// Same unwrapping exception handling as above in above catch block
throwSimpleExceptionIfPossible(state, ae);
throw new SpelEvaluationException( getStartPosition(), ae, SpelMessage.EXCEPTION_DURING_METHOD_INVOCATION,
name, state.getActiveContextObject().getValue().getClass().getName(), ae.getMessage());
}
}
public void setValue(Object newValue) {
throw new IllegalAccessError();
}
public boolean isWritable() {
return false;
}
public final String getName() {
return this.name;
}
@Override
@@ -122,22 +66,21 @@ public class MethodReference extends SpelNodeImpl {
// expressions
try {
state.pushActiveContextObject(state.getRootContextObject());
arguments[i] = children[i].getValueInternal(state).getValue();
arguments[i] = this.children[i].getValueInternal(state).getValue();
}
finally {
state.popActiveContextObject();
}
}
if (currentContext.getValue() == null) {
if (nullSafe) {
if (this.nullSafe) {
return ValueRef.NullValueRef.instance;
}
else {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED,
FormatHelper.formatMethodForMessage(name, getTypes(arguments)));
FormatHelper.formatMethodForMessage(this.name, getTypes(arguments)));
}
}
return new MethodValueRef(state,state.getEvaluationContext(),state.getActiveContextObject().getValue(),arguments);
}
@@ -150,7 +93,7 @@ public class MethodReference extends SpelNodeImpl {
// expressions
try {
state.pushActiveContextObject(state.getRootContextObject());
arguments[i] = children[i].getValueInternal(state).getValue();
arguments[i] = this.children[i].getValueInternal(state).getValue();
}
finally {
state.popActiveContextObject();
@@ -162,7 +105,7 @@ public class MethodReference extends SpelNodeImpl {
}
else {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED,
FormatHelper.formatMethodForMessage(name, getTypes(arguments)));
FormatHelper.formatMethodForMessage(this.name, getTypes(arguments)));
}
}
@@ -196,7 +139,8 @@ public class MethodReference extends SpelNodeImpl {
try {
return executorToUse.execute(
state.getEvaluationContext(), state.getActiveContextObject().getValue(), arguments);
} catch (AccessException ae) {
}
catch (AccessException ae) {
// Same unwrapping exception handling as above in above catch block
throwSimpleExceptionIfPossible(state, ae);
throw new SpelEvaluationException( getStartPosition(), ae, SpelMessage.EXCEPTION_DURING_METHOD_INVOCATION,
@@ -204,7 +148,6 @@ public class MethodReference extends SpelNodeImpl {
}
}
/**
* Decode the AccessException, throwing a lightweight evaluation exception or, if the cause was a RuntimeException,
* throw the RuntimeException directly.
@@ -235,7 +178,7 @@ public class MethodReference extends SpelNodeImpl {
@Override
public String toStringAST() {
StringBuilder sb = new StringBuilder();
sb.append(name).append("(");
sb.append(this.name).append("(");
for (int i = 0; i < getChildCount(); i++) {
if (i > 0)
sb.append(",");
@@ -245,9 +188,9 @@ public class MethodReference extends SpelNodeImpl {
return sb.toString();
}
private MethodExecutor findAccessorForMethod(String name,
List<TypeDescriptor> argumentTypes, ExpressionState state)
private MethodExecutor findAccessorForMethod(String name, List<TypeDescriptor> argumentTypes, ExpressionState state)
throws SpelEvaluationException {
return findAccessorForMethod(name,argumentTypes,state.getActiveContextObject().getValue(),state.getEvaluationContext());
}
@@ -259,19 +202,85 @@ public class MethodReference extends SpelNodeImpl {
if (mResolvers != null) {
for (MethodResolver methodResolver : mResolvers) {
try {
MethodExecutor cEx = methodResolver.resolve(
eContext, contextObject, name, argumentTypes);
MethodExecutor cEx = methodResolver.resolve(eContext, contextObject, name, argumentTypes);
if (cEx != null) {
return cEx;
}
}
catch (AccessException ex) {
throw new SpelEvaluationException(getStartPosition(),ex, SpelMessage.PROBLEM_LOCATING_METHOD, name, contextObject.getClass());
throw new SpelEvaluationException(getStartPosition(),ex, SpelMessage.PROBLEM_LOCATING_METHOD,
name, contextObject.getClass());
}
}
}
throw new SpelEvaluationException(getStartPosition(),SpelMessage.METHOD_NOT_FOUND, FormatHelper.formatMethodForMessage(name, argumentTypes),
throw new SpelEvaluationException(getStartPosition(),SpelMessage.METHOD_NOT_FOUND,
FormatHelper.formatMethodForMessage(name, argumentTypes),
FormatHelper.formatClassNameForMessage(contextObject instanceof Class ? ((Class<?>) contextObject) : contextObject.getClass()));
}
private class MethodValueRef implements ValueRef {
private final ExpressionState state;
private final EvaluationContext evaluationContext;
private final Object target;
private final Object[] arguments;
MethodValueRef(ExpressionState state, EvaluationContext evaluationContext, Object object, Object[] arguments) {
this.state = state;
this.evaluationContext = evaluationContext;
this.target = object;
this.arguments = arguments;
}
public TypedValue getValue() {
MethodExecutor executorToUse = cachedExecutor;
if (executorToUse != null) {
try {
return executorToUse.execute(this.evaluationContext, this.target, this.arguments);
}
catch (AccessException ae) {
// Two reasons this can occur:
// 1. the method invoked actually threw a real exception
// 2. the method invoked was not passed the arguments it expected and has become 'stale'
// In the first case we should not retry, in the second case we should see if there is a
// better suited method.
// To determine which situation it is, the AccessException will contain a cause.
// If the cause is an InvocationTargetException, a user exception was thrown inside the method.
// Otherwise the method could not be invoked.
throwSimpleExceptionIfPossible(this.state, ae);
// at this point we know it wasn't a user problem so worth a retry if a better candidate can be found
cachedExecutor = null;
}
}
// either there was no accessor or it no longer existed
executorToUse = findAccessorForMethod(name, getTypes(this.arguments), this.target, this.evaluationContext);
cachedExecutor = executorToUse;
try {
return executorToUse.execute(this.evaluationContext, this.target, this.arguments);
}
catch (AccessException ae) {
// Same unwrapping exception handling as above in above catch block
throwSimpleExceptionIfPossible(this.state, ae);
throw new SpelEvaluationException( getStartPosition(), ae, SpelMessage.EXCEPTION_DURING_METHOD_INVOCATION,
name, this.state.getActiveContextObject().getValue().getClass().getName(), ae.getMessage());
}
}
public void setValue(Object newValue) {
throw new IllegalAccessError();
}
public boolean isWritable() {
return false;
}
}
}
@@ -42,8 +42,8 @@ import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
/**
* Reflection-based {@link MethodResolver} used by default in
* {@link StandardEvaluationContext} unless explicit method resolvers have been specified.
* Reflection-based {@link MethodResolver} used by default in {@link StandardEvaluationContext}
* unless explicit method resolvers have been specified.
*
* @author Andy Clement
* @author Juergen Hoeller
@@ -63,7 +63,6 @@ public class ReflectiveMethodResolver implements MethodResolver {
public ReflectiveMethodResolver() {
}
/**
@@ -99,7 +98,8 @@ public class ReflectiveMethodResolver implements MethodResolver {
// If a filter is registered for this type, call it
MethodFilter filter = (this.filters != null ? this.filters.get(type) : null);
if (filter != null) {
methods = filter.filter(methods);
List<Method> filtered = filter.filter(methods);
methods = (filtered instanceof ArrayList ? filtered : new ArrayList<Method>(filtered));
}
// Sort methods into a sensible order
@@ -119,7 +119,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
}
// Remove duplicate methods (possible due to resolved bridge methods)
methods = new ArrayList<Method>(new LinkedHashSet<Method>(methods));
Set<Method> methodsToIterate = new LinkedHashSet<Method>(methods);
Method closeMatch = null;
int closeMatchDistance = Integer.MAX_VALUE;
@@ -127,7 +127,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
Method matchRequiringConversion = null;
boolean multipleOptions = false;
for (Method method : methods) {
for (Method method : methodsToIterate) {
if (method.getName().equals(name)) {
Class<?>[] paramTypes = method.getParameterTypes();
List<TypeDescriptor> paramDescriptors = new ArrayList<TypeDescriptor>(paramTypes.length);
@@ -148,9 +148,10 @@ public class ReflectiveMethodResolver implements MethodResolver {
return new ReflectiveMethodExecutor(method, null);
}
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.CLOSE) {
if (!useDistance) {
if (!this.useDistance) {
closeMatch = method;
} else {
}
else {
int matchDistance = ReflectionHelper.getTypeDifferenceWeight(paramDescriptors, argumentTypes);
if (matchDistance<closeMatchDistance) {
// this is a better match
@@ -200,7 +201,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
}
private Method[] getMethods(Class<?> type, Object targetObject) {
if(targetObject instanceof Class) {
if (targetObject instanceof Class) {
Set<Method> methods = new HashSet<Method>();
methods.addAll(Arrays.asList(getMethods(type)));
methods.addAll(Arrays.asList(getMethods(targetObject.getClass())));
@@ -211,9 +212,9 @@ public class ReflectiveMethodResolver implements MethodResolver {
/**
* Return the set of methods for this type. The default implementation returns the
* result of Class#getMethods for the given {@code type}, but subclasses may override
* in order to alter the results, e.g. specifying static methods declared elsewhere.
*
* result of {@link Class#getMethods()} for the given {@code type}, but subclasses
* may override in order to alter the results, e.g. specifying static methods
* declared elsewhere.
* @param type the class for which to return the methods
* @since 3.1.1
*/
@@ -3,6 +3,7 @@ package org.springframework.expression.spel.testresources;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -30,8 +31,8 @@ public class Inventor {
private boolean accessedThroughGetSet;
public List<Integer> listOfInteger = new ArrayList<Integer>();
public List<Boolean> booleanList = new ArrayList<Boolean>();
public Map<String,Boolean> mapOfStringToBoolean = new HashMap<String,Boolean>();
public Map<Integer,String> mapOfNumbersUpToTen = new HashMap<Integer,String>();
public Map<String,Boolean> mapOfStringToBoolean = new LinkedHashMap<String,Boolean>();
public Map<Integer,String> mapOfNumbersUpToTen = new LinkedHashMap<Integer,String>();
public List<Integer> listOfNumbersUpToTen = new ArrayList<Integer>();
public List<Integer> listOneFive = new ArrayList<Integer>();
public String[] stringArrayOfThreeItems = new String[]{"1","2","3"};
@@ -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.
@@ -37,6 +37,7 @@ import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* {@link RowMapper} implementation that converts a row into a new instance
@@ -163,18 +164,19 @@ public class BeanPropertyRowMapper<T> implements RowMapper<T> {
* @return the converted name
*/
private String underscoreName(String name) {
if (!StringUtils.hasLength(name)) {
return "";
}
StringBuilder result = new StringBuilder();
if (name != null && name.length() > 0) {
result.append(name.substring(0, 1).toLowerCase());
for (int i = 1; i < name.length(); i++) {
String s = name.substring(i, i + 1);
if (s.equals(s.toUpperCase())) {
result.append("_");
result.append(s.toLowerCase());
}
else {
result.append(s);
}
result.append(name.substring(0, 1).toLowerCase());
for (int i = 1; i < name.length(); i++) {
String s = name.substring(i, i + 1);
String slc = s.toLowerCase();
if (!s.equals(slc)) {
result.append("_").append(slc);
}
else {
result.append(s);
}
}
return result.toString();
@@ -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,21 +32,22 @@ import javax.jms.TextMessage;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Message converter that uses the Jackson 2 library to convert messages to and from JSON.
* Maps an object to a {@link javax.jms.BytesMessage}, or to a {@link javax.jms.TextMessage} if the
* {@link #setTargetType targetType} is set to {@link org.springframework.jms.support.converter.MessageType#TEXT}.
* Converts from a {@link javax.jms.TextMessage} or {@link javax.jms.BytesMessage} to an object.
* Maps an object to a {@link BytesMessage}, or to a {@link TextMessage} if the
* {@link #setTargetType targetType} is set to {@link MessageType#TEXT}.
* Converts from a {@link TextMessage} or {@link BytesMessage} to an object.
*
* @author Mark Pollack
* @author Dave Syer
* @author Juergen Hoeller
* @since 3.1.4
*/
public class MappingJackson2MessageConverter implements MessageConverter {
public class MappingJackson2MessageConverter implements MessageConverter, BeanClassLoaderAware {
/**
* The default encoding used for writing to text messages: UTF-8.
@@ -68,9 +69,11 @@ public class MappingJackson2MessageConverter implements MessageConverter {
private Map<Class<?>, String> classIdMappings = new HashMap<Class<?>, String>();
private ClassLoader beanClassLoader;
/**
* Specify the {@link org.codehaus.jackson.map.ObjectMapper} to use instead of using the default.
* Specify the {@link ObjectMapper} to use instead of using the default.
*/
public void setObjectMapper(ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "ObjectMapper must not be null");
@@ -78,13 +81,13 @@ public class MappingJackson2MessageConverter implements MessageConverter {
}
/**
* Specify whether {@link #toMessage(Object, javax.jms.Session)} should marshal to a
* {@link javax.jms.BytesMessage} or a {@link javax.jms.TextMessage}.
* <p>The default is {@link org.springframework.jms.support.converter.MessageType#BYTES}, i.e. this converter marshals to
* a {@link javax.jms.BytesMessage}. Note that the default version of this converter
* supports {@link org.springframework.jms.support.converter.MessageType#BYTES} and {@link org.springframework.jms.support.converter.MessageType#TEXT} only.
* @see org.springframework.jms.support.converter.MessageType#BYTES
* @see org.springframework.jms.support.converter.MessageType#TEXT
* Specify whether {@link #toMessage(Object, Session)} should marshal to a
* {@link BytesMessage} or a {@link TextMessage}.
* <p>The default is {@link MessageType#BYTES}, i.e. this converter marshals to
* a {@link BytesMessage}. Note that the default version of this converter
* supports {@link MessageType#BYTES} and {@link MessageType#TEXT} only.
* @see MessageType#BYTES
* @see MessageType#TEXT
*/
public void setTargetType(MessageType targetType) {
Assert.notNull(targetType, "MessageType must not be null");
@@ -142,6 +145,10 @@ public class MappingJackson2MessageConverter implements MessageConverter {
}
}
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
Message message;
@@ -176,15 +183,14 @@ public class MappingJackson2MessageConverter implements MessageConverter {
/**
* Map the given object to a {@link javax.jms.TextMessage}.
* Map the given object to a {@link TextMessage}.
* @param object the object to be mapped
* @param session current JMS session
* @param objectMapper the mapper to use
* @return the resulting message
* @throws javax.jms.JMSException if thrown by JMS methods
* @throws java.io.IOException in case of I/O errors
* @see javax.jms.Session#createBytesMessage
* @see org.springframework.oxm.Marshaller#marshal(Object, javax.xml.transform.Result)
* @throws JMSException if thrown by JMS methods
* @throws IOException in case of I/O errors
* @see Session#createBytesMessage
*/
protected TextMessage mapToTextMessage(Object object, Session session, ObjectMapper objectMapper)
throws JMSException, IOException {
@@ -195,15 +201,14 @@ public class MappingJackson2MessageConverter implements MessageConverter {
}
/**
* Map the given object to a {@link javax.jms.BytesMessage}.
* Map the given object to a {@link BytesMessage}.
* @param object the object to be mapped
* @param session current JMS session
* @param objectMapper the mapper to use
* @return the resulting message
* @throws javax.jms.JMSException if thrown by JMS methods
* @throws java.io.IOException in case of I/O errors
* @see javax.jms.Session#createBytesMessage
* @see org.springframework.oxm.Marshaller#marshal(Object, javax.xml.transform.Result)
* @throws JMSException if thrown by JMS methods
* @throws IOException in case of I/O errors
* @see Session#createBytesMessage
*/
protected BytesMessage mapToBytesMessage(Object object, Session session, ObjectMapper objectMapper)
throws JMSException, IOException {
@@ -222,22 +227,22 @@ public class MappingJackson2MessageConverter implements MessageConverter {
/**
* Template method that allows for custom message mapping.
* Invoked when {@link #setTargetType} is not {@link org.springframework.jms.support.converter.MessageType#TEXT} or
* {@link org.springframework.jms.support.converter.MessageType#BYTES}.
* Invoked when {@link #setTargetType} is not {@link MessageType#TEXT} or
* {@link MessageType#BYTES}.
* <p>The default implementation throws an {@link IllegalArgumentException}.
* @param object the object to marshal
* @param session the JMS Session
* @param objectMapper the mapper to use
* @param targetType the target message type (other than TEXT or BYTES)
* @return the resulting message
* @throws javax.jms.JMSException if thrown by JMS methods
* @throws java.io.IOException in case of I/O errors
* @throws JMSException if thrown by JMS methods
* @throws IOException in case of I/O errors
*/
protected Message mapToMessage(Object object, Session session, ObjectMapper objectMapper, MessageType targetType)
throws JMSException, IOException {
throw new IllegalArgumentException("Unsupported message type [" + targetType +
"]. MappingJacksonMessageConverter by default only supports TextMessages and BytesMessages.");
"]. MappingJackson2MessageConverter by default only supports TextMessages and BytesMessages.");
}
/**
@@ -247,7 +252,7 @@ public class MappingJackson2MessageConverter implements MessageConverter {
* into the configured type id message property.
* @param object the payload object to set a type id for
* @param message the JMS Message to set the type id on
* @throws javax.jms.JMSException if thrown by JMS methods
* @throws JMSException if thrown by JMS methods
* @see #getJavaTypeForMessage(javax.jms.Message)
* @see #setTypeIdPropertyName(String)
* @see #setTypeIdMappings(java.util.Map)
@@ -283,8 +288,8 @@ public class MappingJackson2MessageConverter implements MessageConverter {
* @param message the input message
* @param targetJavaType the target type
* @return the message converted to an object
* @throws javax.jms.JMSException if thrown by JMS
* @throws java.io.IOException in case of I/O errors
* @throws JMSException if thrown by JMS
* @throws IOException in case of I/O errors
*/
protected Object convertFromTextMessage(TextMessage message, JavaType targetJavaType)
throws JMSException, IOException {
@@ -298,8 +303,8 @@ public class MappingJackson2MessageConverter implements MessageConverter {
* @param message the input message
* @param targetJavaType the target type
* @return the message converted to an object
* @throws javax.jms.JMSException if thrown by JMS
* @throws java.io.IOException in case of I/O errors
* @throws JMSException if thrown by JMS
* @throws IOException in case of I/O errors
*/
protected Object convertFromBytesMessage(BytesMessage message, JavaType targetJavaType)
throws JMSException, IOException {
@@ -321,14 +326,14 @@ public class MappingJackson2MessageConverter implements MessageConverter {
/**
* Template method that allows for custom message mapping.
* Invoked when {@link #setTargetType} is not {@link org.springframework.jms.support.converter.MessageType#TEXT} or
* {@link org.springframework.jms.support.converter.MessageType#BYTES}.
* Invoked when {@link #setTargetType} is not {@link MessageType#TEXT} or
* {@link MessageType#BYTES}.
* <p>The default implementation throws an {@link IllegalArgumentException}.
* @param message the input message
* @param targetJavaType the target type
* @return the message converted to an object
* @throws javax.jms.JMSException if thrown by JMS
* @throws java.io.IOException in case of I/O errors
* @throws JMSException if thrown by JMS
* @throws IOException in case of I/O errors
*/
protected Object convertFromMessage(Message message, JavaType targetJavaType)
throws JMSException, IOException {
@@ -344,7 +349,7 @@ public class MappingJackson2MessageConverter implements MessageConverter {
* and consults the configured type id mapping. This can be overridden with
* a different strategy, e.g. doing some heuristics based on message origin.
* @param message the JMS Message to set the type id on
* @throws javax.jms.JMSException if thrown by JMS methods
* @throws JMSException if thrown by JMS methods
* @see #setTypeIdOnMessage(Object, javax.jms.Message)
* @see #setTypeIdPropertyName(String)
* @see #setTypeIdMappings(java.util.Map)
@@ -354,13 +359,13 @@ public class MappingJackson2MessageConverter implements MessageConverter {
if (typeId == null) {
throw new MessageConversionException("Could not find type id property [" + this.typeIdPropertyName + "]");
}
Class mappedClass = this.idClassMappings.get(typeId);
Class<?> mappedClass = this.idClassMappings.get(typeId);
if (mappedClass != null) {
return this.objectMapper.getTypeFactory().constructType(mappedClass);
}
try {
return this.objectMapper.getTypeFactory().constructType(
ClassUtils.forName(typeId, getClass().getClassLoader()));
Class<?> typeClass = ClassUtils.forName(typeId, this.beanClassLoader);
return this.objectMapper.getTypeFactory().constructType(typeClass);
}
catch (Throwable ex) {
throw new MessageConversionException("Failed to resolve type id [" + typeId + "]", ex);
@@ -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.
@@ -28,13 +28,12 @@ import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.xml.transform.Result;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.type.TypeFactory;
import org.codehaus.jackson.type.JavaType;
import org.springframework.oxm.Marshaller;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -49,7 +48,7 @@ import org.springframework.util.ClassUtils;
* @author Juergen Hoeller
* @since 3.1
*/
public class MappingJacksonMessageConverter implements MessageConverter {
public class MappingJacksonMessageConverter implements MessageConverter, BeanClassLoaderAware {
/**
* The default encoding used for writing to text messages: UTF-8.
@@ -71,6 +70,8 @@ public class MappingJacksonMessageConverter implements MessageConverter {
private Map<Class<?>, String> classIdMappings = new HashMap<Class<?>, String>();
private ClassLoader beanClassLoader;
/**
* Specify the {@link ObjectMapper} to use instead of using the default.
@@ -145,6 +146,10 @@ public class MappingJacksonMessageConverter implements MessageConverter {
}
}
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
Message message;
@@ -187,7 +192,6 @@ public class MappingJacksonMessageConverter implements MessageConverter {
* @throws JMSException if thrown by JMS methods
* @throws IOException in case of I/O errors
* @see Session#createBytesMessage
* @see Marshaller#marshal(Object, Result)
*/
protected TextMessage mapToTextMessage(Object object, Session session, ObjectMapper objectMapper)
throws JMSException, IOException {
@@ -206,7 +210,6 @@ public class MappingJacksonMessageConverter implements MessageConverter {
* @throws JMSException if thrown by JMS methods
* @throws IOException in case of I/O errors
* @see Session#createBytesMessage
* @see Marshaller#marshal(Object, Result)
*/
protected BytesMessage mapToBytesMessage(Object object, Session session, ObjectMapper objectMapper)
throws JMSException, IOException {
@@ -357,12 +360,13 @@ public class MappingJacksonMessageConverter implements MessageConverter {
if (typeId == null) {
throw new MessageConversionException("Could not find type id property [" + this.typeIdPropertyName + "]");
}
Class mappedClass = this.idClassMappings.get(typeId);
Class<?> mappedClass = this.idClassMappings.get(typeId);
if (mappedClass != null) {
return TypeFactory.type(mappedClass);
}
try {
return TypeFactory.type(ClassUtils.forName(typeId, getClass().getClassLoader()));
Class<?> typeClass = ClassUtils.forName(typeId, this.beanClassLoader);
return TypeFactory.type(typeClass);
}
catch (Throwable ex) {
throw new MessageConversionException("Failed to resolve type id [" + typeId + "]", ex);
@@ -16,7 +16,6 @@
package org.springframework.orm.jdo;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import javax.jdo.Constants;
@@ -35,8 +34,6 @@ import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* Default implementation of the {@link JdoDialect} interface.
@@ -69,10 +66,6 @@ import org.springframework.util.ReflectionUtils;
*/
public class DefaultJdoDialect implements JdoDialect, PersistenceExceptionTranslator {
// JDO 3.0 setTimeoutMillis method available?
private static final Method setTimeoutMillisMethod =
ClassUtils.getMethodIfAvailable(Query.class, "setTimeoutMillis", Integer.class);
protected final Log logger = LogFactory.getLog(getClass());
private SQLExceptionTranslator jdbcExceptionTranslator;
@@ -213,19 +206,9 @@ public class DefaultJdoDialect implements JdoDialect, PersistenceExceptionTransl
}
/**
* This implementation applies a JDO 3.0 query timeout, if available. Otherwise,
* it sets the JPA 2.0 query hints "javax.persistence.lock.timeout" and
* "javax.persistence.query.timeout", assuming that JDO providers are often
* JPA providers as well.
* This implementation does nothing.
*/
public void applyQueryTimeout(Query query, int remainingTimeInSeconds) throws JDOException {
if (setTimeoutMillisMethod != null) {
ReflectionUtils.invokeMethod(setTimeoutMillisMethod, query, remainingTimeInSeconds);
}
else {
query.addExtension("javax.persistence.lock.timeout", remainingTimeInSeconds);
query.addExtension("javax.persistence.query.timeout", remainingTimeInSeconds);
}
}
@@ -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.
@@ -35,12 +35,13 @@ import org.springframework.orm.jpa.DefaultJpaDialect;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* {@link org.springframework.orm.jpa.JpaDialect} implementation for
* Hibernate EntityManager. Developed against Hibernate 3.3;
* tested against 3.3, 3.5, 3.6 and 4.0 (with the latter including
* Hibernate EntityManager. Developed against Hibernate 3.3; tested
* against 3.3, 3.5, 3.6, 4.0, 4.1 and 4.2 (with the latter including
* Hibernate EntityManager in the Hibernate core distribution).
*
* @author Costin Leau
@@ -147,7 +148,11 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
private final Session session;
private static volatile Method connectionMethod;
// This will find a corresponding method on Hibernate 3.x but not on 4.x
private static final Method sessionConnectionMethod =
ClassUtils.getMethodIfAvailable(Session.class, "connection");
private static volatile Method connectionMethodToUse = sessionConnectionMethod;
public HibernateConnectionHandle(Session session) {
this.session = session;
@@ -155,19 +160,26 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
public Connection getConnection() {
try {
if (connectionMethod == null) {
// reflective lookup to bridge between Hibernate 3.x and 4.x
connectionMethod = this.session.getClass().getMethod("connection");
if (connectionMethodToUse == null) {
// Reflective lookup trying to find SessionImpl's connection() on Hibernate 4.x
connectionMethodToUse = this.session.getClass().getMethod("connection");
}
return (Connection) ReflectionUtils.invokeMethod(connectionMethod, this.session);
return (Connection) ReflectionUtils.invokeMethod(connectionMethodToUse, this.session);
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException("Cannot find connection() method on Hibernate session", ex);
throw new IllegalStateException("Cannot find connection() method on Hibernate Session", ex);
}
}
public void releaseConnection(Connection con) {
JdbcUtils.closeConnection(con);
if (sessionConnectionMethod != null) {
// Need to explicitly call close() with Hibernate 3.x in order to allow
// for eager release of the underlying physical Connection if necessary.
// However, do not do this on Hibernate 4.2+ since it would return the
// physical Connection to the pool right away, making it unusable for
// further operations within the current transaction!
JdbcUtils.closeConnection(con);
}
}
}
@@ -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.
@@ -16,6 +16,8 @@
package org.springframework.orm.jpa.toplink;
import org.junit.Ignore;
import org.springframework.orm.jpa.AbstractContainerEntityManagerFactoryIntegrationTests;
import org.springframework.orm.jpa.EntityManagerFactoryInfo;
@@ -26,6 +28,7 @@ import org.springframework.orm.jpa.EntityManagerFactoryInfo;
* @author Rod Johnson
* @author Juergen Hoeller
*/
@Ignore
public class TopLinkEntityManagerFactoryIntegrationTests extends AbstractContainerEntityManagerFactoryIntegrationTests {
@Override
@@ -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,10 +25,8 @@ import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
@@ -42,62 +40,54 @@ import org.springframework.util.ClassUtils;
* Helper class for {@link Jaxb2Marshaller} that scans given packages for classes marked with JAXB2 annotations.
*
* @author Arjen Poutsma
* @author Juergen Hoeller
* @author David Harrigan
* @since 3.1.1
* @see #scanPackages()
*/
class ClassPathJaxb2TypeScanner {
private static final String RESOURCE_PATTERN = "/**/*.class";
private final TypeFilter[] jaxb2TypeFilters =
new TypeFilter[]{new AnnotationTypeFilter(XmlRootElement.class, false),
new AnnotationTypeFilter(XmlType.class, false), new AnnotationTypeFilter(XmlSeeAlso.class, false),
new AnnotationTypeFilter(XmlEnum.class, false)};
private static final TypeFilter[] JAXB2_TYPE_FILTERS = new TypeFilter[] {
new AnnotationTypeFilter(XmlRootElement.class, false), new AnnotationTypeFilter(XmlType.class, false),
new AnnotationTypeFilter(XmlSeeAlso.class, false), new AnnotationTypeFilter(XmlEnum.class, false)};
private final ResourcePatternResolver resourcePatternResolver;
private final String[] packagesToScan;
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
private List<Class<?>> jaxb2Classes = new ArrayList<Class<?>>();
/** Constructs a new {@code ClassPathJaxb2TypeScanner} for the given packages. */
ClassPathJaxb2TypeScanner(String[] packagesToScan) {
public ClassPathJaxb2TypeScanner(ClassLoader classLoader, String... packagesToScan) {
Assert.notEmpty(packagesToScan, "'packagesToScan' must not be empty");
this.resourcePatternResolver = new PathMatchingResourcePatternResolver(classLoader);
this.packagesToScan = packagesToScan;
}
void setResourceLoader(ResourceLoader resourceLoader) {
if (resourceLoader != null) {
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
}
}
/** Returns the JAXB2 classes found in the specified packages. */
Class<?>[] getJaxb2Classes() {
return jaxb2Classes.toArray(new Class<?>[jaxb2Classes.size()]);
}
/**
* Scans the packages for classes marked with JAXB2 annotations.
*
* Scan the packages for classes marked with JAXB2 annotations.
* @throws UncategorizedMappingException in case of errors
*/
void scanPackages() throws UncategorizedMappingException {
public Class<?>[] scanPackages() throws UncategorizedMappingException {
try {
for (String packageToScan : packagesToScan) {
List<Class<?>> jaxb2Classes = new ArrayList<Class<?>>();
for (String packageToScan : this.packagesToScan) {
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(packageToScan) + RESOURCE_PATTERN;
Resource[] resources = resourcePatternResolver.getResources(pattern);
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
for (Resource resource : resources) {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
if (isJaxb2Class(metadataReader, metadataReaderFactory)) {
String className = metadataReader.getClassMetadata().getClassName();
Class<?> jaxb2AnnotatedClass = resourcePatternResolver.getClassLoader().loadClass(className);
Class<?> jaxb2AnnotatedClass = this.resourcePatternResolver.getClassLoader().loadClass(className);
jaxb2Classes.add(jaxb2AnnotatedClass);
}
}
}
return jaxb2Classes.toArray(new Class<?>[jaxb2Classes.size()]);
}
catch (IOException ex) {
throw new UncategorizedMappingException("Failed to scan classpath for unlisted classes", ex);
@@ -107,8 +97,8 @@ class ClassPathJaxb2TypeScanner {
}
}
private boolean isJaxb2Class(MetadataReader reader, MetadataReaderFactory factory) throws IOException {
for (TypeFilter filter : jaxb2TypeFilters) {
protected boolean isJaxb2Class(MetadataReader reader, MetadataReaderFactory factory) throws IOException {
for (TypeFilter filter : JAXB2_TYPE_FILTERS) {
if (filter.match(reader, factory)) {
return true;
}
@@ -116,5 +106,4 @@ class ClassPathJaxb2TypeScanner {
return false;
}
}
@@ -75,7 +75,6 @@ import org.xml.sax.helpers.XMLReaderFactory;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.JdkVersion;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
@@ -119,9 +118,8 @@ import org.springframework.util.xml.StaxUtils;
* @see #setUnmarshallerListener(javax.xml.bind.Unmarshaller.Listener)
* @see #setAdapters(XmlAdapter[])
*/
public class Jaxb2Marshaller
implements MimeMarshaller, MimeUnmarshaller, GenericMarshaller, GenericUnmarshaller, BeanClassLoaderAware,
ResourceLoaderAware, InitializingBean {
public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, GenericMarshaller, GenericUnmarshaller,
BeanClassLoaderAware, InitializingBean {
private static final String CID = "cid:";
@@ -177,8 +175,8 @@ public class Jaxb2Marshaller
/**
* Set multiple JAXB context paths. The given array of context paths is converted to a
* colon-delimited string, as supported by JAXB.
* Set multiple JAXB context paths. The given array of context paths gets
* converted to a colon-delimited string, as supported by JAXB.
*/
public void setContextPaths(String... contextPaths) {
Assert.notEmpty(contextPaths, "'contextPaths' must not be empty");
@@ -187,8 +185,8 @@ public class Jaxb2Marshaller
/**
* Set a JAXB context path.
* <p>Setting this property, {@link #setClassesToBeBound "classesToBeBound"}, or
* {@link #setPackagesToScan "packagesToScan"} is required.
* <p>Setting either this property, {@link #setClassesToBeBound "classesToBeBound"}
* or {@link #setPackagesToScan "packagesToScan"} is required.
*/
public void setContextPath(String contextPath) {
Assert.hasText(contextPath, "'contextPath' must not be null");
@@ -204,8 +202,8 @@ public class Jaxb2Marshaller
/**
* Set the list of Java classes to be recognized by a newly created JAXBContext.
* <p>Setting this property, {@link #setContextPath "contextPath"}, or
* {@link #setPackagesToScan "packagesToScan"} is required.
* <p>Setting either this property, {@link #setContextPath "contextPath"}
* or {@link #setPackagesToScan "packagesToScan"} is required.
*/
public void setClassesToBeBound(Class<?>... classesToBeBound) {
Assert.notEmpty(classesToBeBound, "'classesToBeBound' must not be empty");
@@ -220,10 +218,11 @@ public class Jaxb2Marshaller
}
/**
* Set the packages to search using Spring-based scanning for classes with JAXB2 annotations in the classpath.
* <p>Setting this property, {@link #setContextPath "contextPath"}, or
* {@link #setClassesToBeBound "classesToBeBound"} is required. This is analogous to Spring's component-scan feature
* ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}).
* Set the packages to search for classes with JAXB2 annotations in the classpath.
* This is using a Spring-bases search and therefore analogous to Spring's component-scan
* feature ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}).
* <p>Setting either this property, {@link #setContextPath "contextPath"}
* or {@link #setClassesToBeBound "classesToBeBound"} is required.
*/
public void setPackagesToScan(String[] packagesToScan) {
this.packagesToScan = packagesToScan;
@@ -390,12 +389,8 @@ public class Jaxb2Marshaller
this.beanClassLoader = classLoader;
}
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public final void afterPropertiesSet() throws Exception {
public void afterPropertiesSet() throws Exception {
boolean hasContextPath = StringUtils.hasLength(this.contextPath);
boolean hasClassesToBeBound = !ObjectUtils.isEmpty(this.classesToBeBound);
boolean hasPackagesToScan = !ObjectUtils.isEmpty(this.packagesToScan);
@@ -487,10 +482,8 @@ public class Jaxb2Marshaller
logger.info("Creating JAXBContext by scanning packages [" +
StringUtils.arrayToCommaDelimitedString(this.packagesToScan) + "]");
}
ClassPathJaxb2TypeScanner scanner = new ClassPathJaxb2TypeScanner(this.packagesToScan);
scanner.setResourceLoader(this.resourceLoader);
scanner.scanPackages();
Class<?>[] jaxb2Classes = scanner.getJaxb2Classes();
ClassPathJaxb2TypeScanner scanner = new ClassPathJaxb2TypeScanner(this.beanClassLoader, this.packagesToScan);
Class<?>[] jaxb2Classes = scanner.scanPackages();
if (logger.isDebugEnabled()) {
logger.debug("Found JAXB2 classes: [" + StringUtils.arrayToCommaDelimitedString(jaxb2Classes) + "]");
}
@@ -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.
@@ -79,10 +79,15 @@ public class Person {
ObjectUtils.nullSafeEquals(this.someBoolean, otherPerson.someBoolean));
}
@Override
public int hashCode() {
return Person.class.hashCode();
}
@Override
public String toString() {
return "Person [name=" + this.name + ", someDouble=" + this.someDouble
+ ", someBoolean=" + this.someBoolean + "]";
}
}
}
@@ -243,11 +243,10 @@ public class MockServletContext implements ServletContext {
}
/**
* This method uses the Java Activation framework, which returns
* "application/octet-stream" when the mime type is unknown (i.e. it never returns
* {@code null}). In order to maintain the {@link ServletContext#getMimeType(String)
* contract, as of version 3.2.2, this method returns null if the mimeType is
* "application/octet-stream".
* This method uses the Java Activation framework, which returns "application/octet-stream"
* when the mime type is unknown (i.e. it never returns {@code null}). In order to maintain
* the {@link ServletContext#getMimeType(String)} contract, this method returns {@code null}
* if the mimeType is "application/octet-stream", as of Spring 3.2.2.
*/
public String getMimeType(String filePath) {
String mimeType = MimeTypeResolver.getMimeType(filePath);
@@ -167,7 +167,8 @@ public class TestContext extends AttributeAccessorSupport {
* context} associated with this test context is <em>dirty</em> and should be
* discarded. Do this if a test has modified the context &mdash; for example,
* by replacing a bean definition or modifying the state of a singleton bean.
* @deprecated As of Spring 3.2.2, use {@link #markApplicationContextDirty(HierarchyMode)} instead.
* @deprecated as of Spring 3.2.2; use
* {@link #markApplicationContextDirty(DirtiesContext.HierarchyMode)} instead.
*/
@Deprecated
public void markApplicationContextDirty() {
@@ -20,6 +20,7 @@ import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
@@ -47,8 +48,8 @@ public class DirtiesContextTestExecutionListener extends AbstractTestExecutionLi
* Marks the {@linkplain ApplicationContext application context} of the supplied
* {@linkplain TestContext test context} as
* {@linkplain TestContext#markApplicationContextDirty() dirty}, and sets the
* {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE
* REINJECT_DEPENDENCIES_ATTRIBUTE} in the test context to {@code true}.
* {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE}
* in the test context to {@code true}.
* @param testContext the test context whose application context should
* marked as dirty
* @deprecated as of Spring 3.2.2, use {@link #dirtyContext(TestContext, HierarchyMode)} instead.
@@ -61,10 +62,10 @@ public class DirtiesContextTestExecutionListener extends AbstractTestExecutionLi
/**
* Marks the {@linkplain ApplicationContext application context} of the supplied
* {@linkplain TestContext test context} as {@linkplain
* TestContext#markApplicationContextDirty(HierarchyMode) dirty} and sets the
* {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE
* REINJECT_DEPENDENCIES_ATTRIBUTE} in the test context to {@code true}.
* {@linkplain TestContext test context} as
* {@linkplain TestContext#markApplicationContextDirty(DirtiesContext.HierarchyMode) dirty}
* and sets {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE}
* in the test context to {@code true}.
* @param testContext the test context whose application context should
* marked as dirty
* @param hierarchyMode the context cache clearing mode to be applied if the
@@ -85,9 +86,8 @@ public class DirtiesContextTestExecutionListener extends AbstractTestExecutionLi
* AFTER_EACH_TEST_METHOD}, the {@linkplain ApplicationContext application
* context} of the test context will be
* {@linkplain TestContext#markApplicationContextDirty() marked as dirty} and the
* {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE
* REINJECT_DEPENDENCIES_ATTRIBUTE} in the test context will be set to
* {@code true}.
* {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE}
* in the test context will be set to {@code true}.
*/
@Override
public void afterTestMethod(TestContext testContext) throws Exception {
@@ -16,13 +16,10 @@
package org.springframework.transaction.annotation;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.util.Map;
import org.junit.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -33,6 +30,9 @@ import org.springframework.tests.transaction.CallCountingTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.AnnotationTransactionNamespaceHandlerTests.TransactionalTestBean;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
/**
* Tests demonstrating use of @EnableTransactionManagement @Configuration classes.
*
@@ -84,9 +84,9 @@ public class EnableTransactionManagementTests {
new AnnotationConfigApplicationContext(EnableAspectJTxConfig.class, TxManagerConfig.class);
fail("should have thrown CNFE when trying to load AnnotationTransactionAspect. " +
"Do you actually have org.springframework.aspects on the classpath?");
} catch (Exception ex) {
System.out.println(ex);
assertThat(ex.getMessage().endsWith("AspectJTransactionManagementConfiguration.class] cannot be opened because it does not exist"), is(true));
}
catch (Exception ex) {
assertThat(ex.getMessage().contains("AspectJTransactionManagementConfiguration"), is(true));
}
}
@@ -85,7 +85,17 @@ public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<R
protected void writeInternal(Resource resource, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
StreamUtils.copy(resource.getInputStream(), outputMessage.getBody());
InputStream in = resource.getInputStream();
try {
StreamUtils.copy(in, outputMessage.getBody());
}
finally {
try {
in.close();
}
catch (IOException ex) {
}
}
outputMessage.getBody().flush();
}
@@ -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,11 +22,6 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
@@ -38,9 +33,14 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* A FactoryBean for creating a Jackson {@link ObjectMapper} with setters to
* enable or disable Jackson features from within XML configuration.
* A {@link FactoryBean} for creating a Jackson 2 {@link ObjectMapper} with setters
* to enable or disable Jackson features from within XML configuration.
*
* <p>Example usage with
* {@link org.springframework.http.converter.json.MappingJackson2HttpMessageConverter}:
@@ -56,7 +56,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule;
* &lt;/bean>
* </pre>
*
* <p>Example usage with {@link org.springframework.web.servlet.view.json.MappingJackson2JsonView}:
* <p>Example usage with MappingJackson2JsonView:
*
* <pre>
* &lt;bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
@@ -94,12 +94,8 @@ import com.fasterxml.jackson.databind.module.SimpleModule;
* &lt;/bean>
* </pre>
*
* <p>Note: This BeanFctory is singleton, so if you need more than one you'll need
* to configure multiple instances.
*
* @author <a href="mailto:dmitry.katsubo@gmail.com">Dmitry Katsubo</a>
* @author Rossen Stoyanchev
*
* @since 3.2
*/
public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper>, InitializingBean {
@@ -127,6 +123,8 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
/**
* Define the format for date/time with the given {@link DateFormat}.
* <p>Note: Setting this property makes the exposed {@link ObjectMapper}
* non-thread-safe, according to Jackson's thread safety rules.
* @see #setSimpleDateFormat(String)
*/
public void setDateFormat(DateFormat dateFormat) {
@@ -135,6 +133,8 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
/**
* Define the date/time format with a {@link SimpleDateFormat}.
* <p>Note: Setting this property makes the exposed {@link ObjectMapper}
* non-thread-safe, according to Jackson's thread safety rules.
* @see #setDateFormat(DateFormat)
*/
public void setSimpleDateFormat(String format) {
@@ -197,8 +197,8 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
* {@link MapperFeature#AUTO_DETECT_GETTERS} option.
*/
public void setAutoDetectGettersSetters(boolean autoDetectGettersSetters) {
this.features.put(MapperFeature.AUTO_DETECT_SETTERS, autoDetectGettersSetters);
this.features.put(MapperFeature.AUTO_DETECT_GETTERS, autoDetectGettersSetters);
this.features.put(MapperFeature.AUTO_DETECT_SETTERS, autoDetectGettersSetters);
}
/**
@@ -217,12 +217,11 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
/**
* Specify features to enable.
*
* @see MapperFeature
* @see SerializationFeature
* @see DeserializationFeature
* @see org.codehaus.jackson.map.JsonParser.Feature
* @see org.codehaus.jackson.map.JsonGenerator.Feature
* @see com.fasterxml.jackson.core.JsonParser.Feature
* @see com.fasterxml.jackson.core.JsonGenerator.Feature
* @see com.fasterxml.jackson.databind.SerializationFeature
* @see com.fasterxml.jackson.databind.DeserializationFeature
* @see com.fasterxml.jackson.databind.MapperFeature
*/
public void setFeaturesToEnable(Object... featuresToEnable) {
if (featuresToEnable != null) {
@@ -234,12 +233,11 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
/**
* Specify features to disable.
*
* @see MapperFeature
* @see SerializationFeature
* @see DeserializationFeature
* @see org.codehaus.jackson.map.JsonParser.Feature
* @see org.codehaus.jackson.map.JsonGenerator.Feature
* @see com.fasterxml.jackson.core.JsonParser.Feature
* @see com.fasterxml.jackson.core.JsonGenerator.Feature
* @see com.fasterxml.jackson.databind.SerializationFeature
* @see com.fasterxml.jackson.databind.DeserializationFeature
* @see com.fasterxml.jackson.databind.MapperFeature
*/
public void setFeaturesToDisable(Object... featuresToDisable) {
if (featuresToDisable != null) {
@@ -249,7 +247,8 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
}
}
public void afterPropertiesSet() throws FatalBeanException {
public void afterPropertiesSet() {
if (this.objectMapper == null) {
this.objectMapper = new ObjectMapper();
}
@@ -258,7 +257,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
this.objectMapper.setDateFormat(this.dateFormat);
}
if (this.serializers != null || this.deserializers != null) {
if (!this.serializers.isEmpty() || !this.deserializers.isEmpty()) {
SimpleModule module = new SimpleModule();
addSerializers(module);
addDeserializers(module);
@@ -289,26 +288,27 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
}
private void configureFeature(Object feature, boolean enabled) {
if (feature instanceof MapperFeature) {
this.objectMapper.configure((MapperFeature) feature, enabled);
}
else if (feature instanceof DeserializationFeature) {
this.objectMapper.configure((DeserializationFeature) feature, enabled);
}
else if (feature instanceof SerializationFeature) {
this.objectMapper.configure((SerializationFeature) feature, enabled);
}
else if (feature instanceof JsonParser.Feature) {
if (feature instanceof JsonParser.Feature) {
this.objectMapper.configure((JsonParser.Feature) feature, enabled);
}
else if (feature instanceof JsonGenerator.Feature) {
this.objectMapper.configure((JsonGenerator.Feature) feature, enabled);
}
else if (feature instanceof SerializationFeature) {
this.objectMapper.configure((SerializationFeature) feature, enabled);
}
else if (feature instanceof DeserializationFeature) {
this.objectMapper.configure((DeserializationFeature) feature, enabled);
}
else if (feature instanceof MapperFeature) {
this.objectMapper.configure((MapperFeature) feature, enabled);
}
else {
throw new FatalBeanException("Unknown feature class " + feature.getClass().getName());
}
}
/**
* Return the singleton ObjectMapper.
*/
@@ -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,8 +32,8 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
/**
* A FactoryBean for creating a Jackson {@link ObjectMapper} with setters to
* enable or disable Jackson features from within XML configuration.
* A {@link FactoryBean} for creating a Jackson {@link ObjectMapper} with setters
* to enable or disable Jackson features from within XML configuration.
*
* <p>Example usage with MappingJacksonHttpMessageConverter:
* <pre>
@@ -104,6 +104,8 @@ public class JacksonObjectMapperFactoryBean implements FactoryBean<ObjectMapper>
/**
* Define the format for date/time with the given {@link DateFormat}.
* <p>Note: Setting this property makes the exposed {@link ObjectMapper}
* non-thread-safe, according to Jackson's thread safety rules.
* @see #setSimpleDateFormat(String)
*/
public void setDateFormat(DateFormat dateFormat) {
@@ -112,6 +114,8 @@ public class JacksonObjectMapperFactoryBean implements FactoryBean<ObjectMapper>
/**
* Define the date/time format with a {@link SimpleDateFormat}.
* <p>Note: Setting this property makes the exposed {@link ObjectMapper}
* non-thread-safe, according to Jackson's thread safety rules.
* @see #setDateFormat(DateFormat)
*/
public void setSimpleDateFormat(String format) {
@@ -132,8 +136,8 @@ public class JacksonObjectMapperFactoryBean implements FactoryBean<ObjectMapper>
* {@link org.codehaus.jackson.map.DeserializationConfig.Feature#AUTO_DETECT_FIELDS}.
*/
public void setAutoDetectFields(boolean autoDetectFields) {
this.features.put(DeserializationConfig.Feature.AUTO_DETECT_FIELDS, autoDetectFields);
this.features.put(SerializationConfig.Feature.AUTO_DETECT_FIELDS, autoDetectFields);
this.features.put(DeserializationConfig.Feature.AUTO_DETECT_FIELDS, autoDetectFields);
}
/**
@@ -161,11 +165,10 @@ public class JacksonObjectMapperFactoryBean implements FactoryBean<ObjectMapper>
/**
* Specify features to enable.
*
* @see org.codehaus.jackson.JsonParser.Feature
* @see org.codehaus.jackson.JsonGenerator.Feature
* @see org.codehaus.jackson.map.SerializationConfig.Feature
* @see org.codehaus.jackson.map.DeserializationConfig.Feature
* @see org.codehaus.jackson.map.JsonParser.Feature
* @see org.codehaus.jackson.map.JsonGenerator.Feature
*/
public void setFeaturesToEnable(Object[] featuresToEnable) {
if (featuresToEnable != null) {
@@ -177,11 +180,10 @@ public class JacksonObjectMapperFactoryBean implements FactoryBean<ObjectMapper>
/**
* Specify features to disable.
*
* @see org.codehaus.jackson.JsonParser.Feature
* @see org.codehaus.jackson.JsonGenerator.Feature
* @see org.codehaus.jackson.map.SerializationConfig.Feature
* @see org.codehaus.jackson.map.DeserializationConfig.Feature
* @see org.codehaus.jackson.map.JsonParser.Feature
* @see org.codehaus.jackson.map.JsonGenerator.Feature
*/
public void setFeaturesToDisable(Object[] featuresToDisable) {
if (featuresToDisable != null) {
@@ -191,6 +193,7 @@ public class JacksonObjectMapperFactoryBean implements FactoryBean<ObjectMapper>
}
}
public void afterPropertiesSet() {
if (this.objectMapper == null) {
this.objectMapper = new ObjectMapper();
@@ -204,28 +207,29 @@ public class JacksonObjectMapperFactoryBean implements FactoryBean<ObjectMapper>
this.objectMapper.getSerializationConfig().setDateFormat(this.dateFormat);
}
for (Map.Entry<Object, Boolean> entry : this.features.entrySet()) {
configureFeature(entry.getKey(), entry.getValue().booleanValue());
configureFeature(entry.getKey(), entry.getValue());
}
}
private void configureFeature(Object feature, boolean enabled) {
if (feature instanceof DeserializationConfig.Feature) {
this.objectMapper.configure((DeserializationConfig.Feature) feature, enabled);
}
else if (feature instanceof SerializationConfig.Feature) {
this.objectMapper.configure((SerializationConfig.Feature) feature, enabled);
}
else if (feature instanceof JsonParser.Feature) {
if (feature instanceof JsonParser.Feature) {
this.objectMapper.configure((JsonParser.Feature) feature, enabled);
}
else if (feature instanceof JsonGenerator.Feature) {
this.objectMapper.configure((JsonGenerator.Feature) feature, enabled);
}
else if (feature instanceof SerializationConfig.Feature) {
this.objectMapper.configure((SerializationConfig.Feature) feature, enabled);
}
else if (feature instanceof DeserializationConfig.Feature) {
this.objectMapper.configure((DeserializationConfig.Feature) feature, enabled);
}
else {
throw new IllegalArgumentException("Unknown feature class: " + feature.getClass().getName());
}
}
/**
* Return the singleton ObjectMapper.
*/
@@ -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.
@@ -16,8 +16,8 @@
package org.springframework.web;
import java.util.List;
import java.util.Collections;
import java.util.List;
import javax.servlet.ServletException;
import org.springframework.http.MediaType;
@@ -33,6 +33,7 @@ public abstract class HttpMediaTypeException extends ServletException {
private final List<MediaType> supportedMediaTypes;
/**
* Create a new HttpMediaTypeException.
* @param message the exception message
@@ -48,13 +49,15 @@ public abstract class HttpMediaTypeException extends ServletException {
*/
protected HttpMediaTypeException(String message, List<MediaType> supportedMediaTypes) {
super(message);
this.supportedMediaTypes = supportedMediaTypes;
this.supportedMediaTypes = Collections.unmodifiableList(supportedMediaTypes);
}
/**
* Return the list of supported media types.
*/
public List<MediaType> getSupportedMediaTypes() {
return supportedMediaTypes;
return this.supportedMediaTypes;
}
}
@@ -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 @@ public class HttpMediaTypeNotSupportedException extends HttpMediaTypeException {
private final MediaType contentType;
/**
* Create a new HttpMediaTypeNotSupportedException.
* @param message the exception message
@@ -61,11 +62,12 @@ public class HttpMediaTypeNotSupportedException extends HttpMediaTypeException {
this.contentType = contentType;
}
/**
* Return the HTTP request content type method that caused the failure.
*/
public MediaType getContentType() {
return contentType;
return this.contentType;
}
}
@@ -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.
@@ -17,9 +17,9 @@
package org.springframework.web;
import java.util.Collection;
import java.util.HashSet;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.servlet.ServletException;
import org.springframework.http.HttpMethod;
@@ -105,11 +105,11 @@ public class HttpRequestMethodNotSupportedException extends ServletException {
* Return the actually supported HTTP methods, if known, as {@link HttpMethod} instances.
*/
public Set<HttpMethod> getSupportedHttpMethods() {
Set<HttpMethod> supportedMethods = new HashSet<HttpMethod>();
Set<HttpMethod> supportedMethods = new LinkedHashSet<HttpMethod>();
for (String value : this.supportedMethods) {
supportedMethods.add(HttpMethod.valueOf(value));
}
return supportedMethods;
return Collections.unmodifiableSet(supportedMethods);
}
}
@@ -50,6 +50,8 @@ import org.springframework.web.context.request.NativeWebRequest;
*/
public class ContentNegotiationManager implements ContentNegotiationStrategy, MediaTypeFileExtensionResolver {
private static final List<MediaType> MEDIA_TYPE_ALL = Arrays.asList(MediaType.ALL);
private final List<ContentNegotiationStrategy> contentNegotiationStrategies =
new ArrayList<ContentNegotiationStrategy>();
@@ -119,9 +121,10 @@ public class ContentNegotiationManager implements ContentNegotiationStrategy, Me
public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException {
for (ContentNegotiationStrategy strategy : this.contentNegotiationStrategies) {
List<MediaType> mediaTypes = strategy.resolveMediaTypes(webRequest);
if (!mediaTypes.isEmpty()) {
return mediaTypes;
if (mediaTypes.isEmpty() || mediaTypes.equals(MEDIA_TYPE_ALL)) {
continue;
}
return mediaTypes;
}
return Collections.emptyList();
}

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