Compare commits

...

126 Commits

Author SHA1 Message Date
Spring Buildmaster fc73f6bb2c Release version 3.2.4.RELEASE 2013-08-06 16:00:04 -07:00
Phillip Webb 119364f326 Further 3.2.4 changelog entries 2013-08-06 15:11:43 -07:00
Arjen Poutsma 434735fbf6 Fix potential security risk when using Spring OXM
Disable by default external entity resolution when using Spring OXM
with jaxb. This prevents a XML entity from being able to resolve a
local file on the host system.

See:
https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing

Issue: SPR-10806
(cherry picked from commit 7576274)
2013-08-06 15:10:05 -07:00
Grzegorz Rożniecki 8f4221deb3 Fix SimpleJdbcCall and SimpleJdbcInsert Javadoc
Change "fluid" interface to "fluent" and "string" to "chain", plus fix
few typos in Javadoc.

Issue: SPR-10792
(cherry picked from commit 2344412)
2013-08-06 14:44:01 -07:00
Juergen Hoeller 2d646ca79e Polishing 2013-08-06 01:58:46 +02:00
Juergen Hoeller 1245919331 Polishing 2013-08-06 01:15:17 +02:00
Juergen Hoeller bcbd338fe2 Further 3.2.4 changelog entries 2013-08-06 00:32:59 +02:00
Juergen Hoeller 945463b826 Added javadoc note on the use of CachingConnectionFactory
Issue: SPR-10581
(cherry picked from commit 2626a35)
2013-08-06 00:31:18 +02:00
Juergen Hoeller 3ba3dd61d1 Consistent use of varargs; deprecated setAnnotatedClass method
Issue: SPR-10421
2013-08-06 00:31:06 +02:00
Juergen Hoeller cd523c7051 Restored overridable getXStream() method in Spring Framework 3.2.x
Also setting the bean class loader on the XStream instance itself now.

Issue: SPR-10421
2013-08-05 23:05:15 +02:00
Juergen Hoeller 20ddd3254b DelegatingFilterProxy avoids synchronization for pre-resolved delegate
Issue: SPR-10413
(cherry picked from commit c26272c)
2013-08-05 22:24:58 +02:00
Juergen Hoeller e30b842316 Fixed ClassFilterAwareUnionMethodMatcher equals implementation
Issue: SPR-10604
(cherry picked from commit f329140)
2013-08-05 22:23:10 +02:00
Rossen Stoyanchev b0675c031e Make date methods in HttpHeaders public
Issue: SPR-10713
2013-08-05 12:46:33 -04:00
Rossen Stoyanchev 0f71da5be6 Return -1 after parse error for Expires header
Issue: SPR-10648
2013-08-05 12:38:53 -04:00
Juergen Hoeller 9035a97e18 Refined javadoc for WebLogic/WebSphere transaction setup
Issue: SPR-10777
2013-08-01 17:24:24 +02:00
Juergen Hoeller d32a77a5f0 Optimized TomcatInstrumentableClassLoader implementation
Issue: SPR-10788
2013-08-01 15:49:58 +02:00
Juergen Hoeller d8e3ef7640 Polishing
Issue: SPR-10752
Issue: SPR-10627
2013-08-01 00:35:51 +02:00
Juergen Hoeller ccb02a2355 Updated changelog for 3.2.4 2013-07-31 23:42:36 +02:00
Juergen Hoeller d0948f1f03 Fixed misunderstanding with respect to excludeUnlistedClasses default in JPA 2.0
Issue: SPR-10767
2013-07-31 23:40:59 +02:00
Juergen Hoeller ae0f23e942 Polishing
Issue: SPR-10752
Issue: SPR-10627
2013-07-31 22:42:27 +02:00
Juergen Hoeller b40263e06b PropertySourcesPlaceholderConfigurer's "ignoreUnresolvablePlaceholders" setting reliably applies to nested placeholders as well
Issue: SPR-10549
(cherry picked from commit 127b91f)
2013-07-31 18:38:31 +02:00
Juergen Hoeller 2f8dfb3e52 Updated Quartz version range in javadoc
Issue: SPR-10775
2013-07-30 23:27:34 +02:00
Juergen Hoeller d5c78c953d Remove the JobDetail from the job data map after discovering it
Issue: SPR-10775
2013-07-30 23:27:33 +02:00
Juergen Hoeller dfac1d0510 Added "requestsRecovery" bean property to JobDetailFactoryBean
Issue: SPR-10775
2013-07-30 23:27:32 +02:00
Juergen Hoeller 14b83c3fcc Polishing
Issue: SPR-10609
2013-07-30 23:27:30 +02:00
Phillip Webb ae6e84bc7d Fix TestNG build settings 2013-07-30 14:21:28 -07:00
Phillip Webb 4213a31a7d Fix failing test due to CUSTOM_COMPILATION Group 2013-07-30 13:54:42 -07:00
Phillip Webb 22454c8edf Upgradle to gradle 1.6 2013-07-30 13:29:05 -07:00
Deline Neo 98da5a7b2b Add attributeDoesNotExist ModelResultMatcher
Issue: SPR-10509
2013-07-30 15:41:55 -04:00
Phillip Webb 0a37552beb Add CUSTOM_COMPILATION TestGroup 2013-07-30 11:54:22 -07:00
Phillip Webb 1b702fa6a2 Revert "Add test source dependency in attempt to fix CI"
This reverts commit a2e438b2be.
2013-07-30 11:53:34 -07:00
Phillip Webb a2e438b2be Add test source dependency in attempt to fix CI 2013-07-30 11:33:30 -07:00
Phillip Webb 9ff9d45283 Minor polish to gradle build 2013-07-30 10:33:52 -07:00
Phillip Webb 1fee4c0c0b Upgradle to gradle 1.6 2013-07-30 10:33:03 -07:00
Rossen Stoyanchev dc87a2211c Make HTTP scheme parsing case-insensitive
Issue: SPR-10779
2013-07-30 12:33:22 -04:00
Phillip Webb 77b7344530 Upgradle to gradle 1.6 2013-07-30 09:29:44 -07:00
Phillip Webb 7cde4f1503 Update gradle plugin versions 2013-07-30 09:22:08 -07:00
Rossen Stoyanchev 6c11fd3b5e Fix issue with parsing x-forwarded-host header
Issue: SPR-10701
2013-07-30 11:48:06 -04:00
Biju Kunjummen eec4a37d1c Fix Jaxb2TypeScanner to scan for @XmlRegistry
Update ClassPathJaxb2TypeScanner to scan for @XmlRegistry classes.

Prior to this commit explicitly configured @XmlRegistry annotated classes
were not registered with the JAXBContext when using the 'packagesToScan'
property of the Jaxb2Unmarshaller.

Issue: SPR-10714
(cherry picked from 4f871d4)
2013-07-29 11:26:52 -07:00
Phillip Webb 1e3dc4aeae Include argument types in MethodReference cache
Update the cached MethodExecutor in MethodReference to include the
method argument types. Prevents the incorrect use of the cache when the
SpEL expression refers to a class that has overloaded methods.

Issue: SPR-10657
(cherry picked from commit f9b12b8)
2013-07-25 11:28:03 +02:00
Phillip Webb d4b54d834e Skip abstract beans in getBeansWithAnnotation()
Update BeanFactory.getBeansWithAnnotation() to skip any abstract
bean definitions.

Issue: SPR-10663
(cherry picked from commit 8ed8ee2)
2013-07-25 11:27:57 +02:00
Juergen Hoeller 3562cd759b Moved executor null check to AsyncExecutionInterceptor, allowing AbstractAsyncExecutionAspect to fall back to sync execution (as in 3.2.1)
Issue: SPR-10636
(cherry picked from commit b6c54c3)
2013-07-25 10:45:59 +02:00
Juergen Hoeller c1dc4e2c75 Resource-based PlatformTransactionManager implementations defensively catch Throwable in doBegin in order to reliably close resource in case of OutOfMemoryError
Issue: SPR-10755
(cherry picked from commit 2e4eb9f)
2013-07-25 10:45:58 +02:00
Phillip Webb 8feeec4a60 Fix ResourceHttpRequestHandler empty location log
Fix ResourceHttpRequestHandler to only log warning when locations
is empty.

Issue: SPR-10780
(cherry picked from bc52469)
2013-07-24 16:52:47 -07:00
Phillip Webb 440a63a3d0 Make TypeDescriptor serializable
Issue: SPR-10631
(cherry picked from 9eb596a)
2013-07-23 14:19:15 -07:00
Phillip Webb 274ed1fe67 Remove unnecessary spring-instrument dependencies
Remove unnecessary spring-core dependency from spring-instrument.

Issue: SPR-10732
(cherry picked from 9939c48)
2013-07-23 13:37:43 -07:00
Phillip Webb 1b47f6c0b0 Add Java 7 instrumentation manifest attributes
Update META-INF/MANIFEST.MF for spring-instrument to include
necessary attributes for running under Java 7:

    Can-Redefine-Classes : true
    Can-Retransform-Classes: true
    Can-Set-Native-Method-Prefix : false

(see http://docs.oracle.com/javase/7/docs/api/java/lang/instrument/
package-summary.html)

Prior to this commit `InstrumentationSavingAgent.getInstrumentation().
addTransformer(t, true);` would fail under Java 7.

Issue: SPR-10731
(Cherry picked from 50333ca)
2013-07-23 13:37:09 -07:00
Phillip Webb 66e4c9b2bb Fix case of rollbackForClassName in ref docs
Update @Transactional reference documentation to fix the case of the
rollbackForClassName and noRollbackForClassName attributes.

Issue: SPR-10754
(cherry picked from 1204d2a)
2013-07-22 15:48:27 -07:00
Nick Williams e608055021 Parse JPA <exclude-unlisted-classes> correctly
Fix PersistenceUnitReader to correctly read <exclude-unlisted-classes>
in both JPA 1.0 and 2.0 persistence.xml files.

Prior to this commit PersistenceUnitReader would set the value of
excludeUnlistedClasses to true when a <exclude-unlisted-classes> element
was present, regardless of its value.

The following rules are now used when parsing:

- If the <exclude-unlisted-classes> element is missing the appropriate
  default value is set (based on the JPA version).

- If an empty <exclude-unlisted-classes/> element is found the
  excludeUnlistedClasses property is set to true.

- Otherwise the value of the <exclude-unlisted-classes> element is used
  to set the excludeUnlistedClasses property.

Issue: SPR-10767
(cherry picked from 7ad540d)

Conflicts:
	spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java
2013-07-22 12:38:46 -07:00
Phillip Webb 199be0ad3c Add spring-core cglib dependency 2013-07-19 14:52:54 -07:00
Phillip Webb af7753eac6 Add MemorySafeUndeclaredThrowableStrategy
Port the latest unreleased UndeclaredThrowableStrategy implementation
from cglib to fix a memory-leak present in v3.

Issue: SPR-10709
(cherry picked from 587877c)
2013-07-19 14:39:24 -07:00
Rossen Stoyanchev cce74b8ba2 Make the JSON prefix used in converters configurable
Issue: SPR-10627
2013-07-19 17:23:33 -04:00
Rossen Stoyanchev dd7508d606 Replace assert w/ warning in ResourceHttpRequestHandl.
Issue: SPR-9186
2013-07-19 17:23:33 -04:00
Rossen Stoyanchev 3bf56dda56 Fix issue in MappingJacksonJsonView
Issue: SPR-10752
2013-07-19 17:23:33 -04:00
Phillip Webb a72209aad3 Make ConfClassPostPro Ordered.HIGHEST_PRECEDENCE
Make ConfigurationClassPostProcessor Ordered.HIGHEST_PRECEDENCE in
case several BeanDefinitionRegistryPostProcessors are registered.

Issue: SPR-10645
(cherry picked from 350cb9b)
2013-07-19 14:16:39 -07:00
Phillip Webb 67f41b15eb Resolve ${} placeholders in @ImportResource
Update ConfigurationClassParser to resolve any ${} placeholders from
@ImportResource values.

Issue: SPR-10686
(cherry picked from commit 700a08e)
2013-07-19 13:14:05 -07:00
Arjen Poutsma 3515acfa3d Added 'processExternalEntities' to JAXB2Marshaller
Added 'processExternalEntities' property to the JAXB2Marshaller, which
indicates whether external XML entities are processed when
unmarshalling.

Default is false, meaning that external entities are not resolved.
Processing of external entities will only be enabled/disabled when the
Source} passed to #unmarshal(Source) is a SAXSource or StreamSource. It
has no effect for DOMSource or StAXSource instances.
2013-07-19 11:07:07 -04:00
Rossen Stoyanchev 7fdd0c22b2 Fix issue in ContentNeogitatingViewResolver
The following commit in 3.2.3 had a side effect on CNVR:
https://github.com/SpringSource/spring-framework/commit/aaded7e30b06cc70a354856a2288acd04045b673

It appears that CNVR doesn't treat a request for "*/*" differently
from a request that does not request content types. Both should be
interpreted as "any content type is acceptable". This fix ensures
that CNVR treats these two cases the same way.

Issue: SPR-10683
2013-07-18 22:03:13 -04:00
Rossen Stoyanchev a0f8a894f2 Cache constructor instance in WebAsyncUtils
Issue: SPR-10673
2013-07-18 17:48:18 -04:00
Phillip Webb 55f02db18e 'Rename' HttpHeaders.getIfNotModifiedSince()
Effectively rename HttpHeaders.getIfNotModifiedSince() to
getIfModifiedSince() by adding a new method and deprecating the
old one.

Issue: SPR-10600
2013-06-26 10:45:33 -07:00
Phillip Webb 71e88cbf30 Fix SQL syntax error in jdbcTemplate update docs
Update the reference guide jdbcTemplate update example to include the
column name.

Issue: SPR-10625
2013-06-25 22:22:36 -07:00
Phillip Webb 514a2e9568 Package RmiInvocationWrapperRTD.xml in jar
Ensure RmiInvocationWrapperRTD.xml is packaged inside spring-context.jar

Issue: SPR-10649

Conflicts:
	build.gradle
2013-06-23 23:52:05 -07:00
Rossen Stoyanchev abfb439bfe Reverse SPR-10402 change that caused 3.2.3 regression
SPR-10402 in Spring Framework 3.2.3 treated empty request parameter
values as missing values, if the empty value was turned into a null
by a PropertyEditor or Converter. This caused the regression.

Issue: SPR-10578, SPR-10402, SPR-10584
2013-06-20 16:25:30 -04:00
Phillip Webb 4ba43b4737 Support meta @Component with non-string value
Update AnnotationBeanNameGenerator to only use the value attribute of
a @Component meta-annotated annotation when it is a String.

Issue: SPR-10580
2013-06-04 10:24:14 -07:00
Spring Buildmaster 2655657a51 2013-05-20 10:18:53 -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
235 changed files with 3752 additions and 2276 deletions
+96 -58
View File
@@ -3,8 +3,8 @@ buildscript {
maven { url "http://repo.springsource.org/plugins-release" }
}
dependencies {
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.3")
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.6")
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.4")
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.7")
}
}
@@ -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"
@@ -58,6 +63,9 @@ configure(allprojects) { project ->
test {
systemProperty("java.awt.headless", "true")
systemProperty("testGroups", project.properties.get("testGroups"))
scanForTestClasses = false
include '**/*Tests.*'
exclude '**/*Abstract*.*'
}
repositories {
@@ -71,25 +79,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 +127,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.
@@ -148,7 +160,7 @@ project("spring-build-src") {
dependencies {
compile gradleApi()
groovy localGroovy()
compile localGroovy()
}
configurations.archives.artifacts.clear()
@@ -219,6 +231,7 @@ project("spring-core") {
cglib("cglib:cglib:${cglibVersion}@jar")
jarjar("com.googlecode.jarjar:jarjar:1.3")
compile(files(cglibRepackJar))
compile(files(asmRepackJar))
compile("commons-logging:commons-logging:1.1.1")
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
@@ -245,6 +258,7 @@ project("spring-core") {
project("spring-beans") {
description = "Spring Beans"
dependencies {
compile(project(":spring-core"))
compile(files(project(":spring-core").cglibRepackJar))
@@ -256,6 +270,7 @@ project("spring-beans") {
project("spring-aop") {
description = "Spring AOP"
dependencies {
compile(project(":spring-core"))
compile(files(project(":spring-core").cglibRepackJar))
@@ -269,6 +284,7 @@ project("spring-aop") {
project("spring-expression") {
description = "Spring Expression Language (SpEL)"
dependencies {
compile(project(":spring-core"))
}
@@ -276,17 +292,19 @@ project("spring-expression") {
project("spring-instrument") {
description = "Spring Instrument"
dependencies {
compile(project(":spring-core"))
}
jar {
manifest.attributes["Premain-Class"] =
"org.springframework.instrument.InstrumentationSavingAgent"
manifest.attributes["Can-Redefine-Classes"] = "true"
manifest.attributes["Can-Retransform-Classes"] = "true"
manifest.attributes["Can-Set-Native-Method-Prefix"] = "false"
}
}
project("spring-instrument-tomcat") {
description = "Spring Instrument Tomcat"
dependencies {
provided("org.apache.tomcat:catalina:6.0.16")
}
@@ -294,6 +312,7 @@ project("spring-instrument-tomcat") {
project("spring-context") {
description = "Spring Context"
dependencies {
optional(project(":spring-instrument"))
compile(project(":spring-aop"))
@@ -306,12 +325,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")
@@ -319,6 +338,9 @@ project("spring-context") {
testCompile("javax.inject:javax.inject-tck:1")
}
// pick up RmiInvocationWrapperRTD.xml in src/main
sourceSets.main.resources.srcDirs += "src/main/java"
test {
jvmArgs = ["-disableassertions:org.aspectj.weaver.UnresolvedType"] // SPR-7989
}
@@ -326,6 +348,7 @@ project("spring-context") {
project("spring-tx") {
description = "Spring Transaction"
dependencies {
optional(project(":spring-context")) // for JCA, @EnableTransactionManagement
optional(project(":spring-aop"))
@@ -355,10 +378,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 +394,7 @@ project("spring-oxm") {
project("spring-jms") {
description = "Spring JMS"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-beans"))
@@ -391,6 +413,7 @@ project("spring-jms") {
project("spring-jdbc") {
description = "Spring JDBC"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-beans"))
@@ -407,6 +430,7 @@ project("spring-jdbc") {
project("spring-context-support") {
description = "Spring Context Support"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-beans"))
@@ -443,8 +467,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 +475,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 +511,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 +541,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 +554,7 @@ project("spring-orm-hibernate4") {
project("spring-webmvc") {
description = "Spring Web MVC"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-expression"))
@@ -541,7 +567,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 +575,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 +614,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 +645,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")
@@ -636,21 +664,6 @@ project("spring-webmvc-portlet") {
project("spring-test") {
description = "Spring TestContext Framework"
task testNG(type: Test) {
useTestNG()
// "TestCase" classes are run by other test classes, not the build.
exclude "**/*TestCase.class"
// Generate TestNG reports alongside JUnit reports.
testReport true
}
test {
dependsOn testNG
useJUnit()
// "TestCase" classes are run by other test classes, not the build.
exclude(["**/*TestCase.class", "**/*TestSuite.class"])
}
dependencies {
compile(project(":spring-core"))
optional(project(":spring-beans"))
@@ -675,6 +688,26 @@ project("spring-test") {
testCompile "org.slf4j:slf4j-jcl:${slf4jVersion}"
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
}
task testNG(type: Test) {
useTestNG()
scanForTestClasses = false
include "**/testng/*.*"
exclude "**/FailingBeforeAndAfterMethodsTests.class"
// "TestCase" classes are run by other test classes, not the build.
exclude "**/*TestCase.class"
// Generate TestNG reports alongside JUnit reports.
testReport true
}
test {
dependsOn testNG
useJUnit()
exclude "**/testng/*.*"
// "TestCase" classes are run by other test classes, not the build.
exclude(["**/*TestCase.class", "**/*TestSuite.class"])
}
}
project("spring-test-mvc") {
@@ -695,11 +728,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 +761,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 +779,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 +792,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 +800,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 +821,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 +847,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 +860,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" },
@@ -959,7 +997,7 @@ configure(rootProject) {
task wrapper(type: Wrapper) {
description = "Generates gradlew[.bat] scripts"
gradleVersion = "1.3"
gradleVersion = "1.6"
doLast() {
def gradleOpts = "-XX:MaxPermSize=1024m -Xmx1024m"
@@ -49,7 +49,7 @@ import org.gradle.api.tasks.TaskAction
public class DetectSplitPackagesPlugin implements Plugin<Project> {
public void apply(Project project) {
def tasks = project.tasks
Task detectSplitPackages = tasks.add("detectSplitPackages", DetectSplitPackagesTask.class)
Task detectSplitPackages = tasks.create("detectSplitPackages", DetectSplitPackagesTask.class)
if (tasks.asMap.containsKey("check")) {
tasks.getByName("check").dependsOn detectSplitPackages
}
@@ -67,8 +67,8 @@ class MergePlugin implements Plugin<Project> {
project.plugins.apply(IdeaPlugin)
MergeModel model = project.extensions.create("merge", MergeModel)
project.configurations.add("merging")
Configuration runtimeMerge = project.configurations.add("runtimeMerge")
project.configurations.create("merging")
Configuration runtimeMerge = project.configurations.create("runtimeMerge")
// Ensure the IDE can reference merged projects
project.eclipse.classpath.plusConfigurations += [runtimeMerge]
@@ -121,7 +121,7 @@ class MergePlugin implements Plugin<Project> {
project.configurations.each { configuration ->
Conf2ScopeMapping mapping = project.conf2ScopeMappings.getMapping([configuration])
if(mapping.scope) {
Configuration intoConfiguration = project.merge.into.configurations.add(
Configuration intoConfiguration = project.merge.into.configurations.create(
project.name + "-" + configuration.name)
configuration.excludeRules.each {
configuration.exclude([
+1 -1
View File
@@ -1 +1 @@
version=3.2.3.BUILD-SNAPSHOT
version=3.2.4.RELEASE
Binary file not shown.
+4 -4
View File
@@ -1,6 +1,6 @@
#Wed Nov 28 09:14:59 PST 2012
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
#Tue Jul 30 09:29:28 PDT 2013
zipStoreBase=GRADLE_USER_HOME
distributionUrl=http\://services.gradle.org/distributions/gradle-1.6-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-1.3-bin.zip
distributionBase=GRADLE_USER_HOME
@@ -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.
@@ -34,7 +34,7 @@ import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;
import org.springframework.cglib.transform.impl.UndeclaredThrowableStrategy;
import org.springframework.cglib.transform.impl.MemorySafeUndeclaredThrowableStrategy;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInvocation;
@@ -181,7 +181,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));
enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setInterceptDuringConstruction(false);
@@ -87,7 +87,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
/**
* Determine the specific executor to use when executing the given method.
* @return the executor to use (never {@code null})
* @return the executor to use (or {@code null}, but just if no default executor has been set)
*/
protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
AsyncTaskExecutor executor = this.executors.get(method);
@@ -101,8 +101,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
this.beanFactory, Executor.class, qualifier);
}
else if (executorToUse == null) {
throw new IllegalStateException("No executor qualifier specified and no default executor set on " +
getClass().getSimpleName() + " either");
return null;
}
executor = (executorToUse instanceof AsyncTaskExecutor ?
(AsyncTaskExecutor) executorToUse : new TaskExecutorAdapter(executorToUse));
@@ -82,7 +82,13 @@ public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
Future<?> result = determineAsyncExecutor(specificMethod).submit(
AsyncTaskExecutor executor = determineAsyncExecutor(specificMethod);
if (executor == null) {
throw new IllegalStateException(
"No executor specified and no default executor set on AsyncExecutionInterceptor either");
}
Future<?> result = executor.submit(
new Callable<Object>() {
public Object call() throws Exception {
try {
@@ -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.
@@ -102,8 +102,9 @@ public abstract class MethodMatchers {
@SuppressWarnings("serial")
private static class UnionMethodMatcher implements IntroductionAwareMethodMatcher, Serializable {
private MethodMatcher mm1;
private MethodMatcher mm2;
private final MethodMatcher mm1;
private final MethodMatcher mm2;
public UnionMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) {
Assert.notNull(mm1, "First MethodMatcher must not be null");
@@ -168,6 +169,7 @@ public abstract class MethodMatchers {
private static class ClassFilterAwareUnionMethodMatcher extends UnionMethodMatcher {
private final ClassFilter cf1;
private final ClassFilter cf2;
public ClassFilterAwareUnionMethodMatcher(MethodMatcher mm1, ClassFilter cf1, MethodMatcher mm2, ClassFilter cf2) {
@@ -191,11 +193,17 @@ public abstract class MethodMatchers {
if (this == other) {
return true;
}
if (!(other instanceof ClassFilterAwareUnionMethodMatcher)) {
if (!super.equals(other)) {
return false;
}
ClassFilterAwareUnionMethodMatcher that = (ClassFilterAwareUnionMethodMatcher) other;
return (this.cf1.equals(that.cf1) && this.cf2.equals(that.cf2) && super.equals(other));
ClassFilter otherCf1 = ClassFilter.TRUE;
ClassFilter otherCf2 = ClassFilter.TRUE;
if (other instanceof ClassFilterAwareUnionMethodMatcher) {
ClassFilterAwareUnionMethodMatcher cfa = (ClassFilterAwareUnionMethodMatcher) other;
otherCf1 = cfa.cf1;
otherCf2 = cfa.cf2;
}
return (this.cf1.equals(otherCf1) && this.cf2.equals(otherCf2));
}
}
@@ -206,8 +214,9 @@ public abstract class MethodMatchers {
@SuppressWarnings("serial")
private static class IntersectionMethodMatcher implements IntroductionAwareMethodMatcher, Serializable {
private MethodMatcher mm1;
private MethodMatcher mm2;
private final MethodMatcher mm1;
private final MethodMatcher mm2;
public IntersectionMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) {
Assert.notNull(mm1, "First MethodMatcher must not be null");
@@ -43,6 +43,7 @@ public final class MethodMatchersTests {
private final Method IOTHER_ABSQUATULATE;
public MethodMatchersTests() throws Exception {
EXCEPTION_GETMESSAGE = Exception.class.getMethod("getMessage", (Class[]) null);
ITESTBEAN_GETAGE = ITestBean.class.getMethod("getAge", (Class[]) null);
@@ -50,6 +51,7 @@ public final class MethodMatchersTests {
IOTHER_ABSQUATULATE = IOther.class.getMethod("absquatulate", (Class[]) null);
}
@Test
public void testDefaultMatchesAll() throws Exception {
MethodMatcher defaultMm = MethodMatcher.TRUE;
@@ -99,23 +101,33 @@ public final class MethodMatchersTests {
assertTrue("Matched setAge method", union.matches(ITESTBEAN_SETAGE, TestBean.class));
assertTrue("Matched getAge method", union.matches(ITESTBEAN_GETAGE, TestBean.class));
assertFalse("Didn't matched absquatulate method", union.matches(IOTHER_ABSQUATULATE, TestBean.class));
}
@Test
public void testUnionEquals() {
MethodMatcher first = MethodMatchers.union(MethodMatcher.TRUE, MethodMatcher.TRUE);
MethodMatcher second = new ComposablePointcut(MethodMatcher.TRUE).union(new ComposablePointcut(MethodMatcher.TRUE)).getMethodMatcher();
assertTrue(first.equals(second));
assertTrue(second.equals(first));
}
public static class StartsWithMatcher extends StaticMethodMatcher {
private String prefix;
private final String prefix;
public StartsWithMatcher(String s) {
this.prefix = s;
}
@Override
public boolean matches(Method m, Class<?> targetClass) {
return m.getName().startsWith(prefix);
}
}
private static class TestDynamicMethodMatcherWhichMatches extends DynamicMethodMatcher {
@Override
public boolean matches(Method m, Class<?> targetClass, Object[] args) {
return true;
@@ -123,6 +135,7 @@ public final class MethodMatchersTests {
}
private static class TestDynamicMethodMatcherWhichDoesNotMatch extends DynamicMethodMatcher {
@Override
public boolean matches(Method m, Class<?> targetClass, Object[] args) {
return false;
+4 -4
View File
@@ -12,8 +12,8 @@ configurations {
tasks.getByName("idea").onlyIf { false }
tasks.getByName("ideaModule").onlyIf { false }
task compileJava(overwrite: true) {
dependsOn JavaPlugin.PROCESS_RESOURCES_TASK_NAME
compileJava {
actions = []
dependsOn configurations.ajc.getTaskDependencyFromProjectDependency(true, "compileJava")
def outputDir = project.sourceSets.main.output.classesDir
@@ -44,8 +44,8 @@ task compileJava(overwrite: true) {
}
}
task compileTestJava(overwrite: true) {
dependsOn JavaPlugin.PROCESS_TEST_RESOURCES_TASK_NAME
compileTestJava {
actions = []
dependsOn configurations.ajc.getTaskDependencyFromProjectDependency(true, "compileTestJava")
dependsOn jar
@@ -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);
}
@@ -31,7 +31,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -460,12 +459,15 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) {
Set<String> beanNames = new LinkedHashSet<String>(getBeanDefinitionCount());
beanNames.addAll(Arrays.asList(getBeanDefinitionNames()));
beanNames.addAll(Arrays.asList(getSingletonNames()));
Map<String, Object> results = new LinkedHashMap<String, Object>();
for (String beanName : beanNames) {
if (findAnnotationOnBean(beanName, annotationType) != null) {
for (String beanName : getBeanDefinitionNames()) {
BeanDefinition beanDefinition = getBeanDefinition(beanName);
if (!beanDefinition.isAbstract() && findAnnotationOnBean(beanName, annotationType) != null) {
results.put(beanName, getBean(beanName));
}
}
for (String beanName : getSingletonNames()) {
if (!results.containsKey(beanName) && findAnnotationOnBean(beanName, annotationType) != null) {
results.put(beanName, getBean(beanName));
}
}
@@ -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();
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="abstractFactoryBean" class="org.springframework.beans.factory.FactoryBeanTests$AbstractFactoryBean" abstract="true"/>
</beans>
@@ -26,6 +26,7 @@ import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
/**
@@ -38,6 +39,7 @@ public final class FactoryBeanTests {
private static final Class<?> CLASS = FactoryBeanTests.class;
private static final Resource RETURNS_NULL_CONTEXT = qualifiedResource(CLASS, "returnsNull.xml");
private static final Resource WITH_AUTOWIRING_CONTEXT = qualifiedResource(CLASS, "withAutowiring.xml");
private static final Resource ABSTRACT_CONTEXT = qualifiedResource(CLASS, "abstract.xml");
@Test
public void testFactoryBeanReturnsNull() throws Exception {
@@ -80,6 +82,20 @@ public final class FactoryBeanTests {
assertSame(gamma, beta.getGamma());
}
@Test
public void testAbstractFactoryBeanViaAnnotation() throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(ABSTRACT_CONTEXT);
factory.getBeansWithAnnotation(Component.class);
}
@Test
public void testAbstractFactoryBeanViaType() throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(ABSTRACT_CONTEXT);
factory.getBeansOfType(AbstractFactoryBean.class);
}
public static class NullReturningFactoryBean implements FactoryBean<Object> {
@@ -152,6 +168,7 @@ public final class FactoryBeanTests {
}
@Component
public static class BetaFactoryBean implements FactoryBean<Object> {
private Beta beta;
@@ -176,4 +193,7 @@ public final class FactoryBeanTests {
}
}
public abstract static class AbstractFactoryBean implements FactoryBean<Object> {
}
}
@@ -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-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.
@@ -30,7 +30,7 @@ import org.springframework.util.ReflectionUtils;
* JobFactory implementation that supports {@link java.lang.Runnable}
* objects as well as standard Quartz {@link org.quartz.Job} instances.
*
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
*
* @author Juergen Hoeller
* @since 2.0
@@ -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,7 +47,7 @@ import org.springframework.util.Assert;
* Use Quartz 2.0's native {@code JobDetailImpl} class or the new Quartz 2.0
* builder API instead. Alternatively, switch to Spring's {@link CronTriggerFactoryBean}
* which largely is a drop-in replacement for this class and its properties and
* consistently works against Quartz 1.x as well as Quartz 2.0/2.1.
* consistently works against Quartz 1.x as well as Quartz 2.x.
*
* @author Juergen Hoeller
* @since 18.02.2004
@@ -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.
@@ -49,7 +49,7 @@ import org.springframework.util.ReflectionUtils;
* to automatically register a trigger for the corresponding JobDetail,
* instead of registering the JobDetail separately.
*
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.0/2.1,
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.x,
* in contrast to the older {@link CronTriggerBean} class.
*
* @author Juergen Hoeller
@@ -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.
@@ -39,7 +39,7 @@ import org.springframework.context.ApplicationContextAware;
* Use Quartz 2.0's native {@code JobDetailImpl} class or the new Quartz 2.0
* builder API instead. Alternatively, switch to Spring's {@link JobDetailFactoryBean}
* which largely is a drop-in replacement for this class and its properties and
* consistently works against Quartz 1.x as well as Quartz 2.0/2.1.
* consistently works against Quartz 1.x as well as Quartz 2.x.
*
* @author Juergen Hoeller
* @since 18.02.2004
@@ -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.
@@ -39,7 +39,7 @@ import org.springframework.context.ApplicationContextAware;
* sensible defaults. This class uses the Spring bean name as job name,
* and the Quartz default group ("DEFAULT") as job group if not specified.
*
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.0/2.1,
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.x,
* in contrast to the older {@link JobDetailBean} class.
*
* @author Juergen Hoeller
@@ -62,6 +62,8 @@ public class JobDetailFactoryBean
private boolean durability = false;
private boolean requestsRecovery = false;
private String description;
private String beanName;
@@ -132,6 +134,14 @@ public class JobDetailFactoryBean
this.durability = durability;
}
/**
* Set the recovery flag for this job, i.e. whether or not the job should
* get re-executed if a 'recovery' or 'fail-over' situation is encountered.
*/
public void setRequestsRecovery(boolean requestsRecovery) {
this.requestsRecovery = requestsRecovery;
}
/**
* Set a textual description for this job.
*/
@@ -209,6 +219,7 @@ public class JobDetailFactoryBean
pvs.add("jobClass", this.jobClass);
pvs.add("jobDataMap", this.jobDataMap);
pvs.add("durability", this.durability);
pvs.add("requestsRecovery", this.requestsRecovery);
pvs.add("description", this.description);
bw.setPropertyValues(pvs);
this.jobDetail = (JobDetail) bw.getWrappedInstance();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -67,7 +67,7 @@ import org.springframework.util.ReflectionUtils;
* You need to implement your own Quartz Job as a thin wrapper for each case
* where you want a persistent job to delegate to a specific service method.
*
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
*
* @author Juergen Hoeller
* @author Alef Arendsen
@@ -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,7 +51,7 @@ import org.springframework.util.ReflectionUtils;
* <p>For concrete usage, check out the {@link SchedulerFactoryBean} and
* {@link SchedulerAccessorBean} classes.
*
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
*
* @author Juergen Hoeller
* @since 2.5.6
@@ -397,7 +397,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
else {
try {
Map jobDataMap = (Map) ReflectionUtils.invokeMethod(Trigger.class.getMethod("getJobDataMap"), trigger);
return (JobDetail) jobDataMap.get(JobDetailAwareTrigger.JOB_DETAIL_KEY);
return (JobDetail) jobDataMap.remove(JobDetailAwareTrigger.JOB_DETAIL_KEY);
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException("Inconsistent Quartz API: " + 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.
@@ -29,7 +29,7 @@ import org.springframework.beans.factory.ListableBeanFactory;
* Spring bean-style class for accessing a Quartz Scheduler, i.e. for registering jobs,
* triggers and listeners on a given {@link org.quartz.Scheduler} instance.
*
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
*
* @author Juergen Hoeller
* @since 2.5.6
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -74,7 +74,7 @@ import org.springframework.util.CollectionUtils;
* automatically apply to Scheduler operations performed within those scopes.
* Alternatively, you may add transactional advice for the Scheduler itself.
*
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
*
* @author Juergen Hoeller
* @since 18.02.2004
@@ -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 @@ import org.springframework.core.Constants;
* Use Quartz 2.0's native {@code JobDetailImpl} class or the new Quartz 2.0
* builder API instead. Alternatively, switch to Spring's {@link SimpleTriggerFactoryBean}
* which largely is a drop-in replacement for this class and its properties and
* consistently works against Quartz 1.x as well as Quartz 2.0/2.1.
* consistently works against Quartz 1.x as well as Quartz 2.x.
*
* @author Juergen Hoeller
* @since 18.02.2004
@@ -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.
@@ -49,7 +49,7 @@ import org.springframework.util.ReflectionUtils;
* to automatically register a trigger for the corresponding JobDetail,
* instead of registering the JobDetail separately.
*
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.0/2.1,
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.x,
* in contrast to the older {@link SimpleTriggerBean} class.
*
* @author Juergen Hoeller
@@ -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,7 +37,7 @@ import org.springframework.util.ReflectionUtils;
* as bean property values. If no matching bean property is found, the entry
* is by default simply ignored. This is analogous to QuartzJobBean's behavior.
*
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
*
* @author Juergen Hoeller
* @since 2.0
@@ -25,6 +25,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cache.Cache;
@@ -61,23 +62,25 @@ import org.springframework.util.StringUtils;
*/
public abstract class CacheAspectSupport implements InitializingBean {
public interface Invoker {
Object invoke();
}
private static final String CACHEABLE = "cacheable";
private static final String UPDATE = "cacheupdate";
private static final String EVICT = "cacheevict";
protected final Log logger = LogFactory.getLog(getClass());
private final ExpressionEvaluator evaluator = new ExpressionEvaluator();
private CacheManager cacheManager;
private CacheOperationSource cacheOperationSource;
private final ExpressionEvaluator evaluator = new ExpressionEvaluator();
private KeyGenerator keyGenerator = new DefaultKeyGenerator();
private boolean initialized = false;
private static final String CACHEABLE = "cacheable", UPDATE = "cacheupdate", EVICT = "cacheevict";
/**
* Set the CacheManager that this cache aspect should delegate to.
@@ -101,10 +104,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
*/
public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) {
Assert.notEmpty(cacheOperationSources);
this.cacheOperationSource =
(cacheOperationSources.length > 1 ?
new CompositeCacheOperationSource(cacheOperationSources) :
cacheOperationSources[0]);
this.cacheOperationSource = (cacheOperationSources.length > 1 ?
new CompositeCacheOperationSource(cacheOperationSources) : cacheOperationSources[0]);
}
/**
@@ -134,13 +135,14 @@ public abstract class CacheAspectSupport implements InitializingBean {
throw new IllegalStateException("'cacheManager' is required");
}
if (this.cacheOperationSource == null) {
throw new IllegalStateException("The 'cacheOperationSources' property is required: "
+ "If there are no cacheable methods, then don't use a cache aspect.");
throw new IllegalStateException("The 'cacheOperationSources' property is required: " +
"If there are no cacheable methods, then don't use a cache aspect.");
}
this.initialized = true;
}
/**
* Convenience method to return a String representation of this Method
* for use in logging. Can be overridden in subclasses to provide a
@@ -161,7 +163,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
for (String cacheName : cacheNames) {
Cache cache = this.cacheManager.getCache(cacheName);
if (cache == null) {
throw new IllegalArgumentException("Cannot find cache named [" + cacheName + "] for " + operation);
throw new IllegalArgumentException("Cannot find cache named '" + cacheName + "' for " + operation);
}
caches.add(cache);
}
@@ -186,39 +188,31 @@ public abstract class CacheAspectSupport implements InitializingBean {
if (targetClass == null && target != null) {
targetClass = target.getClass();
}
final Collection<CacheOperation> cacheOp = getCacheOperationSource().getCacheOperations(method, targetClass);
Collection<CacheOperation> cacheOp = getCacheOperationSource().getCacheOperations(method, targetClass);
// analyze caching information
if (!CollectionUtils.isEmpty(cacheOp)) {
Map<String, Collection<CacheOperationContext>> ops = createOperationContext(cacheOp, method, args, target, targetClass);
// start with evictions
inspectBeforeCacheEvicts(ops.get(EVICT));
// follow up with cacheable
CacheStatus status = inspectCacheables(ops.get(CACHEABLE));
Object retVal = null;
Object retVal;
Map<CacheOperationContext, Object> updates = inspectCacheUpdates(ops.get(UPDATE));
if (status != null) {
if (status.updateRequired) {
updates.putAll(status.cUpdates);
updates.putAll(status.cacheUpdates);
}
// return cached object
else {
return status.retVal;
}
}
retVal = invoker.invoke();
inspectAfterCacheEvicts(ops.get(EVICT), retVal);
if (!updates.isEmpty()) {
update(updates, retVal);
}
return retVal;
}
@@ -229,27 +223,20 @@ public abstract class CacheAspectSupport implements InitializingBean {
inspectCacheEvicts(evictions, true, ExpressionEvaluator.NO_RESULT);
}
private void inspectAfterCacheEvicts(Collection<CacheOperationContext> evictions,
Object result) {
private void inspectAfterCacheEvicts(Collection<CacheOperationContext> evictions, Object result) {
inspectCacheEvicts(evictions, false, result);
}
private void inspectCacheEvicts(Collection<CacheOperationContext> evictions,
boolean beforeInvocation, Object result) {
private void inspectCacheEvicts(Collection<CacheOperationContext> evictions, boolean beforeInvocation, Object result) {
if (!evictions.isEmpty()) {
boolean log = logger.isTraceEnabled();
for (CacheOperationContext context : evictions) {
CacheEvictOperation evictOp = (CacheEvictOperation) context.operation;
if (beforeInvocation == evictOp.isBeforeInvocation()) {
if (context.isConditionPassing(result)) {
// for each cache
// lazy key initialization
Object key = null;
for (Cache cache : context.getCaches()) {
// cache-wide flush
if (evictOp.isCacheWide()) {
@@ -257,7 +244,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
if (log) {
logger.trace("Invalidating entire cache for operation " + evictOp + " on method " + context.method);
}
} else {
}
else {
// check key
if (key == null) {
key = context.generateKey();
@@ -268,7 +256,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
cache.evict(key);
}
}
} else {
}
else {
if (log) {
logger.trace("Cache condition failed on method " + context.method + " for operation " + context.operation);
}
@@ -279,34 +268,27 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
private CacheStatus inspectCacheables(Collection<CacheOperationContext> cacheables) {
Map<CacheOperationContext, Object> cUpdates = new LinkedHashMap<CacheOperationContext, Object>(cacheables.size());
Map<CacheOperationContext, Object> cacheUpdates = new LinkedHashMap<CacheOperationContext, Object>(cacheables.size());
boolean updateRequired = false;
Object retVal = null;
if (!cacheables.isEmpty()) {
boolean log = logger.isTraceEnabled();
boolean atLeastOnePassed = false;
for (CacheOperationContext context : cacheables) {
if (context.isConditionPassing()) {
atLeastOnePassed = true;
Object key = context.generateKey();
if (log) {
logger.trace("Computed cache key " + key + " for operation " + context.operation);
}
if (key == null) {
throw new IllegalArgumentException(
"Null key returned for cache operation (maybe you are using named params on classes without debug info?) "
+ context.operation);
throw new IllegalArgumentException("Null key returned for cache operation (maybe you " +
"are using named params on classes without debug info?) " + context.operation);
}
// add op/key (in case an update is discovered later on)
cUpdates.put(context, key);
cacheUpdates.put(context, key);
boolean localCacheHit = false;
// check whether the cache needs to be inspected or not (the method will be invoked anyway)
if (!updateRequired) {
for (Cache cache : context.getCaches()) {
@@ -318,7 +300,6 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
}
}
if (!localCacheHit) {
updateRequired = true;
}
@@ -330,51 +311,31 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
}
// return a status only if at least on cacheable matched
// return a status only if at least one cacheable matched
if (atLeastOnePassed) {
return new CacheStatus(cUpdates, updateRequired, retVal);
return new CacheStatus(cacheUpdates, updateRequired, retVal);
}
}
return null;
}
private static class CacheStatus {
// caches/key
final Map<CacheOperationContext, Object> cUpdates;
final boolean updateRequired;
final Object retVal;
CacheStatus(Map<CacheOperationContext, Object> cUpdates, boolean updateRequired, Object retVal) {
this.cUpdates = cUpdates;
this.updateRequired = updateRequired;
this.retVal = retVal;
}
}
private Map<CacheOperationContext, Object> inspectCacheUpdates(Collection<CacheOperationContext> updates) {
Map<CacheOperationContext, Object> cUpdates = new LinkedHashMap<CacheOperationContext, Object>(updates.size());
Map<CacheOperationContext, Object> cacheUpdates = new LinkedHashMap<CacheOperationContext, Object>(updates.size());
if (!updates.isEmpty()) {
boolean log = logger.isTraceEnabled();
for (CacheOperationContext context : updates) {
if (context.isConditionPassing()) {
Object key = context.generateKey();
if (log) {
logger.trace("Computed cache key " + key + " for operation " + context.operation);
}
if (key == null) {
throw new IllegalArgumentException(
"Null key returned for cache operation (maybe you are using named params on classes without debug info?) "
+ context.operation);
throw new IllegalArgumentException("Null key returned for cache operation (maybe you " +
"are using named params on classes without debug info?) " + context.operation);
}
// add op/key (in case an update is discovered later on)
cUpdates.put(context, key);
cacheUpdates.put(context, key);
}
else {
if (log) {
@@ -383,14 +344,13 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
}
}
return cUpdates;
return cacheUpdates;
}
private void update(Map<CacheOperationContext, Object> updates, Object retVal) {
for (Map.Entry<CacheOperationContext, Object> entry : updates.entrySet()) {
CacheOperationContext operationContext = entry.getKey();
if(operationContext.canPutToCache(retVal)) {
if (operationContext.canPutToCache(retVal)) {
for (Cache cache : operationContext.getCaches()) {
cache.put(entry.getValue(), retVal);
}
@@ -398,37 +358,40 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
}
private Map<String, Collection<CacheOperationContext>> createOperationContext(Collection<CacheOperation> cacheOp,
Method method, Object[] args, Object target, Class<?> targetClass) {
Map<String, Collection<CacheOperationContext>> map = new LinkedHashMap<String, Collection<CacheOperationContext>>(3);
private Map<String, Collection<CacheOperationContext>> createOperationContext(
Collection<CacheOperation> cacheOperations, Method method, Object[] args, Object target, Class<?> targetClass) {
Map<String, Collection<CacheOperationContext>> result = new LinkedHashMap<String, Collection<CacheOperationContext>>(3);
Collection<CacheOperationContext> cacheables = new ArrayList<CacheOperationContext>();
Collection<CacheOperationContext> evicts = new ArrayList<CacheOperationContext>();
Collection<CacheOperationContext> updates = new ArrayList<CacheOperationContext>();
for (CacheOperation cacheOperation : cacheOp) {
for (CacheOperation cacheOperation : cacheOperations) {
CacheOperationContext opContext = getOperationContext(cacheOperation, method, args, target, targetClass);
if (cacheOperation instanceof CacheableOperation) {
cacheables.add(opContext);
}
if (cacheOperation instanceof CacheEvictOperation) {
evicts.add(opContext);
}
if (cacheOperation instanceof CachePutOperation) {
updates.add(opContext);
}
}
map.put(CACHEABLE, cacheables);
map.put(EVICT, evicts);
map.put(UPDATE, updates);
return map;
result.put(CACHEABLE, cacheables);
result.put(EVICT, evicts);
result.put(UPDATE, updates);
return result;
}
public interface Invoker {
Object invoke();
}
protected class CacheOperationContext {
private final CacheOperation operation;
@@ -459,8 +422,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
protected boolean isConditionPassing(Object result) {
if (StringUtils.hasText(this.operation.getCondition())) {
EvaluationContext evaluationContext = createEvaluationContext(result);
return evaluator.condition(this.operation.getCondition(), this.method,
evaluationContext);
return evaluator.condition(this.operation.getCondition(), this.method, evaluationContext);
}
return true;
}
@@ -473,7 +435,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
else if (this.operation instanceof CachePutOperation) {
unless = ((CachePutOperation) this.operation).getUnless();
}
if(StringUtils.hasText(unless)) {
if (StringUtils.hasText(unless)) {
EvaluationContext evaluationContext = createEvaluationContext(value);
return !evaluator.unless(unless, this.method, evaluationContext);
}
@@ -493,12 +455,29 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
private EvaluationContext createEvaluationContext(Object result) {
return evaluator.createEvaluationContext(this.caches, this.method, this.args,
this.target, this.targetClass, result);
return evaluator.createEvaluationContext(this.caches, this.method, this.args, this.target, this.targetClass, result);
}
protected Collection<Cache> getCaches() {
return this.caches;
}
}
private static class CacheStatus {
// caches/key
final Map<CacheOperationContext, Object> cacheUpdates;
final boolean updateRequired;
final Object retVal;
CacheStatus(Map<CacheOperationContext, Object> cacheUpdates, boolean updateRequired, Object retVal) {
this.cacheUpdates = cacheUpdates;
this.updateRequired = updateRequired;
this.retVal = retVal;
}
}
}
@@ -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.
@@ -116,7 +116,10 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
(metaAnnotationTypes != null && metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME)) ||
annotationType.equals("javax.annotation.ManagedBean") ||
annotationType.equals("javax.inject.Named");
return (isStereotype && attributes != null && attributes.containsKey("value"));
return (isStereotype && attributes != null &&
attributes.containsKey("value") &&
attributes.get("value") instanceof String);
}
/**
@@ -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
@@ -239,7 +213,8 @@ class ConfigurationClassParser {
String[] resources = importResource.getStringArray("value");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
configClass.addImportedResource(resource, readerClass);
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
@@ -252,7 +227,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 +255,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 +322,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 +462,7 @@ class ConfigurationClassParser {
return this.propertySources;
}
public ImportRegistry getImportRegistry() {
ImportRegistry getImportRegistry() {
return this.importStack;
}
@@ -85,7 +85,7 @@ import static org.springframework.context.annotation.AnnotationConfigUtils.*;
* @since 3.0
*/
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware, Ordered {
private static final String IMPORT_AWARE_PROCESSOR_BEAN_NAME =
ConfigurationClassPostProcessor.class.getName() + ".importAwareProcessor";
@@ -368,6 +368,11 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
}
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
private static class ImportAwareBeanPostProcessor implements PriorityOrdered, BeanFactoryAware, BeanPostProcessor {
@@ -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,6 +20,7 @@ import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.core.Conventions;
@@ -37,14 +38,14 @@ import org.springframework.stereotype.Component;
*/
abstract class ConfigurationClassUtils {
private static final Log logger = LogFactory.getLog(ConfigurationClassUtils.class);
private static final String CONFIGURATION_CLASS_FULL = "full";
private static final String CONFIGURATION_CLASS_LITE = "lite";
private static final String CONFIGURATION_CLASS_ATTRIBUTE =
Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
private static final Log logger = LogFactory.getLog(ConfigurationClassUtils.class);
/**
@@ -93,7 +94,7 @@ abstract class ConfigurationClassUtils {
}
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
return isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata);
return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata));
}
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
@@ -101,12 +102,11 @@ abstract class ConfigurationClassUtils {
}
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
return !metadata.isInterface() && // not an interface or an annotation
(metadata.isAnnotated(Component.class.getName()) ||
metadata.hasAnnotatedMethods(Bean.class.getName()));
// Do not consider an interface or an annotation...
return (!metadata.isInterface() && (
metadata.isAnnotated(Component.class.getName()) || metadata.hasAnnotatedMethods(Bean.class.getName())));
}
/**
* Determine whether the given bean definition indicates a full @Configuration class.
*/
@@ -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.
@@ -108,8 +108,8 @@ public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerS
* <p>Processing occurs by replacing ${...} placeholders in bean definitions by resolving each
* against this configurer's set of {@link PropertySources}, which includes:
* <ul>
* <li>all {@linkplain org.springframework.core.env.ConfigurableEnvironment#getPropertySources environment property sources}, if an
* {@code Environment} {@linkplain #setEnvironment is present}
* <li>all {@linkplain org.springframework.core.env.ConfigurableEnvironment#getPropertySources
* environment property sources}, if an {@code Environment} {@linkplain #setEnvironment is present}
* <li>{@linkplain #mergeProperties merged local properties}, if {@linkplain #setLocation any}
* {@linkplain #setLocations have} {@linkplain #setProperties been}
* {@linkplain #setPropertiesArray specified}
@@ -135,7 +135,7 @@ public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerS
}
try {
PropertySource<?> localPropertySource =
new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, this.mergeProperties());
new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties());
if (this.localOverride) {
this.propertySources.addFirst(localPropertySource);
}
@@ -148,7 +148,7 @@ public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerS
}
}
this.processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
}
/**
@@ -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;
@@ -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.
@@ -98,15 +98,14 @@ public class ReflectiveLoadTimeWeaver implements LoadTimeWeaver {
this.classLoader = classLoader;
this.addTransformerMethod = ClassUtils.getMethodIfAvailable(
this.classLoader.getClass(), ADD_TRANSFORMER_METHOD_NAME,
new Class [] {ClassFileTransformer.class});
new Class[] {ClassFileTransformer.class});
if (this.addTransformerMethod == null) {
throw new IllegalStateException(
"ClassLoader [" + classLoader.getClass().getName() + "] does NOT provide an " +
"'addTransformer(ClassFileTransformer)' method.");
}
this.getThrowawayClassLoaderMethod = ClassUtils.getMethodIfAvailable(
this.classLoader.getClass(), GET_THROWAWAY_CLASS_LOADER_METHOD_NAME,
new Class[0]);
this.classLoader.getClass(), GET_THROWAWAY_CLASS_LOADER_METHOD_NAME, new Class[0]);
// getThrowawayClassLoader method is optional
if (this.getThrowawayClassLoaderMethod == null) {
if (logger.isInfoEnabled()) {
@@ -119,7 +118,7 @@ public class ReflectiveLoadTimeWeaver implements LoadTimeWeaver {
public void addTransformer(ClassFileTransformer transformer) {
Assert.notNull(transformer, "Transformer must not be null");
ReflectionUtils.invokeMethod(this.addTransformerMethod, this.classLoader, new Object[] {transformer});
ReflectionUtils.invokeMethod(this.addTransformerMethod, this.classLoader, transformer);
}
public ClassLoader getInstrumentableClassLoader() {
@@ -128,11 +127,11 @@ public class ReflectiveLoadTimeWeaver implements LoadTimeWeaver {
public ClassLoader getThrowawayClassLoader() {
if (this.getThrowawayClassLoaderMethod != null) {
return (ClassLoader) ReflectionUtils.invokeMethod(this.getThrowawayClassLoaderMethod, this.classLoader,
new Object[0]);
return (ClassLoader) ReflectionUtils.invokeMethod(this.getThrowawayClassLoaderMethod, this.classLoader);
}
else {
return new SimpleThrowawayClassLoader(this.classLoader);
}
}
}
@@ -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
@@ -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,16 +16,21 @@
package org.springframework.context.annotation;
import example.scannable.DefaultNamedComponent;
import org.junit.Test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.Test;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import example.scannable.DefaultNamedComponent;
import static org.junit.Assert.*;
/**
@@ -81,6 +86,22 @@ public class AnnotationBeanNameGeneratorTests {
assertEquals(expectedGeneratedBeanName, beanName);
}
@Test
public void testGenerateBeanNameFromMetaComponentWithStringValue() {
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(ComponentFromStringMeta.class);
String beanName = this.beanNameGenerator.generateBeanName(bd, registry);
assertEquals("henry", beanName);
}
@Test
public void testGenerateBeanNameFromMetaComponentWithNonStringValue() {
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(ComponentFromNonStringMeta.class);
String beanName = this.beanNameGenerator.generateBeanName(bd, registry);
assertEquals("annotationBeanNameGeneratorTests.ComponentFromNonStringMeta", beanName);
}
@Component("walden")
private static class ComponentWithName {
@@ -96,4 +117,19 @@ public class AnnotationBeanNameGeneratorTests {
private static class AnonymousComponent {
}
@Service("henry")
private static class ComponentFromStringMeta {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Component
public @interface NonStringMetaComponent {
long value();
}
@NonStringMetaComponent(123)
private static class ComponentFromNonStringMeta {
}
}
@@ -16,14 +16,17 @@
package org.springframework.context.annotation.configuration;
import java.util.Collections;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -34,6 +37,8 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
/**
* Integration tests for {@link ImportResource} support.
@@ -178,4 +183,22 @@ public class ImportResourceTests {
reader=XmlBeanDefinitionReader.class)
static class SubResourceConfig extends ImportNonXmlResourceConfig {
}
@Test
public void importWithPlaceHolder() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
PropertySource<?> propertySource = new MapPropertySource("test",
Collections.<String, Object> singletonMap("test", "springframework"));
ctx.getEnvironment().getPropertySources().addFirst(propertySource);
ctx.register(ImportXmlConfig.class);
ctx.refresh();
assertTrue("did not contain xml-declared bean", ctx.containsBean("xmlDeclaredBean"));
}
@Configuration
@ImportResource("classpath:org/${test}/context/annotation/configuration/ImportXmlConfig-context.xml")
static class ImportWithPlaceHolder {
}
}
@@ -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 {}
}
@@ -153,6 +153,25 @@ public class PropertyResourceConfigurerIntegrationTests {
}
}
@Test
public void testPropertyPlaceholderConfigurerWithNestedUnresolvableReference() {
StaticApplicationContext ac = new StaticApplicationContext();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("name", "name${var}");
ac.registerSingleton("tb1", TestBean.class, pvs);
pvs = new MutablePropertyValues();
pvs.add("properties", "var=${m}var\nm=${var2}\nvar2=${m2}");
ac.registerSingleton("configurer1", PropertyPlaceholderConfigurer.class, pvs);
try {
ac.refresh();
fail("Should have thrown BeanDefinitionStoreException");
}
catch (BeanDefinitionStoreException ex) {
// expected
ex.printStackTrace();
}
}
@Ignore // this test was breaking after the 3.0 repackaging
@Test
public void testPropertyPlaceholderConfigurerWithAutowireByType() {
@@ -39,8 +39,6 @@ import org.springframework.mock.env.MockPropertySource;
import org.springframework.tests.sample.beans.TestBean;
/**
* Unit tests for {@link PropertySourcesPlaceholderConfigurer}.
*
* @author Chris Beams
* @since 3.1
*/
@@ -139,7 +137,9 @@ public class PropertySourcesPlaceholderConfigurerTests {
PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer();
pc.setPropertySources(propertySources);
pc.setProperties(new Properties() {{ put("my.name", "local"); }});
pc.setProperties(new Properties() {{
put("my.name", "local");
}});
pc.setIgnoreUnresolvablePlaceholders(true);
pc.postProcessBeanFactory(bf);
assertThat(bf.getBean(TestBean.class).getName(), equalTo("${my.name}"));
@@ -172,6 +172,38 @@ public class PropertySourcesPlaceholderConfigurerTests {
assertThat(bf.getBean(TestBean.class).getName(), equalTo("${my.name}"));
}
@Test(expected=BeanDefinitionStoreException.class)
public void nestedUnresolvablePlaceholder() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("testBean",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${my.name}")
.getBeanDefinition());
PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer();
pc.setProperties(new Properties() {{
put("my.name", "${bogus}");
}});
pc.postProcessBeanFactory(bf); // should throw
}
@Test
public void ignoredNestedUnresolvablePlaceholder() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("testBean",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${my.name}")
.getBeanDefinition());
PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer();
pc.setProperties(new Properties() {{
put("my.name", "${bogus}");
}});
pc.setIgnoreUnresolvablePlaceholders(true);
pc.postProcessBeanFactory(bf);
assertThat(bf.getBean(TestBean.class).getName(), equalTo("${bogus}"));
}
@Test
public void withNonEnumerablePropertySource() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
@@ -213,7 +245,8 @@ public class PropertySourcesPlaceholderConfigurerTests {
ppc.postProcessBeanFactory(bf);
if (override) {
assertThat(bf.getBean(TestBean.class).getName(), equalTo("local"));
} else {
}
else {
assertThat(bf.getBean(TestBean.class).getName(), equalTo("enclosing"));
}
}
@@ -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]"));
}
/**
@@ -0,0 +1,54 @@
/*
* 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.cglib.transform.impl;
import org.springframework.cglib.core.ClassGenerator;
import org.springframework.cglib.core.DefaultGeneratorStrategy;
import org.springframework.cglib.core.TypeUtils;
import org.springframework.cglib.transform.ClassTransformer;
import org.springframework.cglib.transform.MethodFilter;
import org.springframework.cglib.transform.MethodFilterTransformer;
import org.springframework.cglib.transform.TransformingClassGenerator;
/**
* Memory safe variant of {@link UndeclaredThrowableStrategy} ported from the latest
* as yet unreleased cglib code.
*/
public class MemorySafeUndeclaredThrowableStrategy extends DefaultGeneratorStrategy {
private static final MethodFilter TRANSFORM_FILTER = new MethodFilter() {
public boolean accept(int access, String name, String desc, String signature,
String[] exceptions) {
return !TypeUtils.isPrivate(access) && name.indexOf('$') < 0;
}
};
private Class wrapper;
public MemorySafeUndeclaredThrowableStrategy(Class wrapper) {
this.wrapper = wrapper;
}
protected ClassGenerator transform(ClassGenerator cg) throws Exception {
ClassTransformer tr = new UndeclaredThrowableTransformer(wrapper);
tr = new MethodFilterTransformer(TRANSFORM_FILTER, tr);
return new TransformingClassGenerator(cg, tr);
}
}
@@ -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());
}
@@ -16,6 +16,7 @@
package org.springframework.core.convert;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
@@ -38,7 +39,10 @@ import org.springframework.util.ObjectUtils;
* @author Sam Brannen
* @since 3.0
*/
public class TypeDescriptor {
public class TypeDescriptor implements Serializable {
private static final long serialVersionUID = 1L;
static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
@@ -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,25 +16,22 @@
package org.springframework.core.env;
import static java.lang.String.format;
import static org.springframework.util.SystemPropertyUtils.PLACEHOLDER_PREFIX;
import static org.springframework.util.SystemPropertyUtils.PLACEHOLDER_SUFFIX;
import static org.springframework.util.SystemPropertyUtils.VALUE_SEPARATOR;
import java.util.LinkedHashSet;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.util.PropertyPlaceholderHelper;
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
import org.springframework.util.SystemPropertyUtils;
/**
* Abstract base class for resolving properties against any underlying source.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
*/
public abstract class AbstractPropertyResolver implements ConfigurablePropertyResolver {
@@ -44,15 +41,20 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
protected ConfigurableConversionService conversionService = new DefaultConversionService();
private PropertyPlaceholderHelper nonStrictHelper;
private PropertyPlaceholderHelper strictHelper;
private boolean ignoreUnresolvableNestedPlaceholders = false;
private String placeholderPrefix = PLACEHOLDER_PREFIX;
private String placeholderSuffix = PLACEHOLDER_SUFFIX;
private String valueSeparator = VALUE_SEPARATOR;
private String placeholderPrefix = SystemPropertyUtils.PLACEHOLDER_PREFIX;
private String placeholderSuffix = SystemPropertyUtils.PLACEHOLDER_SUFFIX;
private String valueSeparator = SystemPropertyUtils.VALUE_SEPARATOR;
private final Set<String> requiredProperties = new LinkedHashSet<String>();
public ConfigurableConversionService getConversionService() {
return this.conversionService;
}
@@ -63,12 +65,12 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
public String getProperty(String key, String defaultValue) {
String value = getProperty(key);
return value == null ? defaultValue : value;
return (value != null ? value : defaultValue);
}
public <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
T value = getProperty(key, targetType);
return value == null ? defaultValue : value;
return (value != null ? value : defaultValue);
}
public void setRequiredProperties(String... requiredProperties) {
@@ -92,7 +94,7 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
public String getRequiredProperty(String key) throws IllegalStateException {
String value = getProperty(key);
if (value == null) {
throw new IllegalStateException(format("required key [%s] not found", key));
throw new IllegalStateException(String.format("required key [%s] not found", key));
}
return value;
}
@@ -100,7 +102,7 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
public <T> T getRequiredProperty(String key, Class<T> valueType) throws IllegalStateException {
T value = getProperty(key, valueType);
if (value == null) {
throw new IllegalStateException(format("required key [%s] not found", key));
throw new IllegalStateException(String.format("required key [%s] not found", key));
}
return value;
}
@@ -130,17 +132,17 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
}
public String resolvePlaceholders(String text) {
if (nonStrictHelper == null) {
nonStrictHelper = createPlaceholderHelper(true);
if (this.nonStrictHelper == null) {
this.nonStrictHelper = createPlaceholderHelper(true);
}
return doResolvePlaceholders(text, nonStrictHelper);
return doResolvePlaceholders(text, this.nonStrictHelper);
}
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
if (strictHelper == null) {
strictHelper = createPlaceholderHelper(false);
if (this.strictHelper == null) {
this.strictHelper = createPlaceholderHelper(false);
}
return doResolvePlaceholders(text, strictHelper);
return doResolvePlaceholders(text, this.strictHelper);
}
/**
@@ -154,15 +156,19 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
/**
* Resolve placeholders within the given string, deferring to the value of
* {@link #setIgnoreUnresolvableNestedPlaceholders(boolean)} to determine whether any
* {@link #setIgnoreUnresolvableNestedPlaceholders} to determine whether any
* unresolvable placeholders should raise an exception or be ignored.
* <p>Invoked from {@link #getProperty} and its variants, implicitly resolving
* nested placeholders. In contrast, {@link #resolvePlaceholders} and
* {@link #resolveRequiredPlaceholders} do <emphasis>not</emphasis> delegate
* to this method but rather perform their own handling of unresolvable
* placeholders, as specified by each of those methods.
* @since 3.2
* @see #setIgnoreUnresolvableNestedPlaceholders(boolean)
* @see #setIgnoreUnresolvableNestedPlaceholders
*/
protected String resolveNestedPlaceholders(String value) {
return this.ignoreUnresolvableNestedPlaceholders ?
this.resolvePlaceholders(value) :
this.resolveRequiredPlaceholders(value);
resolvePlaceholders(value) : resolveRequiredPlaceholders(value);
}
private PropertyPlaceholderHelper createPlaceholderHelper(boolean ignoreUnresolvablePlaceholders) {
@@ -171,11 +177,19 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
}
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
return helper.replacePlaceholders(text, new PlaceholderResolver() {
return helper.replacePlaceholders(text, new PropertyPlaceholderHelper.PlaceholderResolver() {
public String resolvePlaceholder(String placeholderName) {
return getProperty(placeholderName);
return getPropertyAsRawString(placeholderName);
}
});
}
/**
* Retrieve the specified property as a raw String,
* i.e. without resolution of nested placeholders.
* @param key the property name to resolve
* @return the property value or {@code null} if none found
*/
protected abstract String getPropertyAsRawString(String key);
}

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