mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
320 Commits
v3.0.4.RELEASE
...
3.0.x
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f9593da1c | |||
| aac21fdcec | |||
| dfd75352d3 | |||
| 6316448453 | |||
| 40015e3de3 | |||
| 5e448af903 | |||
| 1f3ce640c9 | |||
| cca44f411e | |||
| 9b0412f35f | |||
| 7eee3b9926 | |||
| b5a279d2c8 | |||
| 0862a29066 | |||
| 8d83f6966e | |||
| ce5117c9ed | |||
| 836e3c9253 | |||
| 2006eecb18 | |||
| 91287828f7 | |||
| efd2fc7688 | |||
| 74b5487a28 | |||
| 2882ae29b2 | |||
| 4a7b96c4ca | |||
| 7398e0ea97 | |||
| beaad20795 | |||
| 1bd84db56e | |||
| 6316a45927 | |||
| e298c202af | |||
| 288408e89f | |||
| 53a244d408 | |||
| 8213d0cb50 | |||
| b9868a498e | |||
| df7bdfa7c6 | |||
| f8402e9f82 | |||
| 7eeb654eec | |||
| b558c62953 | |||
| d64dd1943f | |||
| bffa50e31a | |||
| 143cb50986 | |||
| b3ccc438af | |||
| 94513c1a28 | |||
| c9607fdaf2 | |||
| 7c108c1e77 | |||
| 77372d7cdb | |||
| 173f307ec9 | |||
| 2c987b0ffb | |||
| 46a4ac9628 | |||
| c2997f4dd9 | |||
| 0150000d8b | |||
| cad5eb836c | |||
| c82dab6497 | |||
| e6f4e16219 | |||
| d0032f43c7 | |||
| 8a43dd172c | |||
| 11aaefffbf | |||
| c6b36cc207 | |||
| 5856db6f72 | |||
| 3c5e02a54a | |||
| db0c921313 | |||
| 641bc35a50 | |||
| c166803d41 | |||
| 12e1784a99 | |||
| bfabd58106 | |||
| 540845e613 | |||
| 8e7982397c | |||
| 84890ebc0d | |||
| a9f28575b1 | |||
| a730bf47df | |||
| b5ec65cef6 | |||
| 965c12b0f8 | |||
| 7187029ef6 | |||
| 6363bb4b5b | |||
| 58ea5a702d | |||
| 97b988ade8 | |||
| 227234288f | |||
| 05a7b65d43 | |||
| cee6cb859d | |||
| 19c6a4e209 | |||
| b9089a8f9d | |||
| 7a20ed7d70 | |||
| 99588950d2 | |||
| a2129a132f | |||
| 0f1c10bc1c | |||
| 585745de32 | |||
| 65077d262c | |||
| da36c2b8b8 | |||
| 8f01770f29 | |||
| c51b9a7be2 | |||
| 3ffc0a2da2 | |||
| acac25b2eb | |||
| cb0c0c503f | |||
| 215ccc2e10 | |||
| d95cbe23ee | |||
| ac1ffff9db | |||
| c0257aba9b | |||
| 79aa661dd6 | |||
| 18540debf6 | |||
| 7605707c18 | |||
| d48c3b5d4f | |||
| b122cf87df | |||
| 183523d045 | |||
| a4f62bb863 | |||
| 80def4b695 | |||
| 42e18e6c4e | |||
| d8767774c9 | |||
| f67e726be7 | |||
| 41b9a461df | |||
| 037497cb4f | |||
| 3ecb6b1a03 | |||
| 6b92f66ebd | |||
| 070a723ef2 | |||
| d4be29e661 | |||
| 3a3f15f144 | |||
| 3edf8566ed | |||
| a2f00f205a | |||
| 340a8b28f9 | |||
| 83c5753ae1 | |||
| 67bb044a6f | |||
| 9ddfb375cb | |||
| 6fc6a9e80c | |||
| f18fa08aa0 | |||
| aa4ecdb79e | |||
| 8041f6abdd | |||
| 210c77ddb0 | |||
| 24cb345b6c | |||
| 0fdd7550b8 | |||
| f1fb0e5330 | |||
| d4c2f63160 | |||
| b167f3f7a6 | |||
| 63fe7bdd34 | |||
| 270db64243 | |||
| 15fd972417 | |||
| 10d9860457 | |||
| 01eab03dca | |||
| eb50eec85b | |||
| 4faa5af3f8 | |||
| 218e64cc80 | |||
| b82edcca04 | |||
| d8a4949faf | |||
| 22739bebf3 | |||
| fece2c1125 | |||
| 8b55b34d79 | |||
| d1e998bedd | |||
| 2ddb14ae5b | |||
| ae74fbdd4b | |||
| 28769e906f | |||
| 47c21bf73b | |||
| 59fda2dbab | |||
| 43f8eca91b | |||
| 6cb6bd751e | |||
| 58d68cef98 | |||
| 5f3f30fdb4 | |||
| 7a6b2cfe1f | |||
| a8ab9af002 | |||
| ca19b14f13 | |||
| 175f6d4bc5 | |||
| 0206845341 | |||
| a37a9e8a38 | |||
| 577755d580 | |||
| 610812949f | |||
| 82ec515e59 | |||
| d418eed56f | |||
| 244c96151e | |||
| 92298469bf | |||
| bfd54f4f35 | |||
| c5e53ee432 | |||
| 8c9b64c948 | |||
| 171f1ee097 | |||
| be21358db7 | |||
| 5da5fc6499 | |||
| c7aaa85ef6 | |||
| a25e4d794e | |||
| 3c067e5db6 | |||
| 0f924820e8 | |||
| 1f1577e33e | |||
| e1dbb66798 | |||
| 1933b648c3 | |||
| 5cb06f5da2 | |||
| ffa4ed093f | |||
| 4c73a29f99 | |||
| 0195b0da3c | |||
| 27a10c74d1 | |||
| 7893b3ebf6 | |||
| 21d6883139 | |||
| a6569a2930 | |||
| d9d7fb6f9a | |||
| 4108927b28 | |||
| ac5b1bcfab | |||
| c5c1d70aa3 | |||
| 043ec2c8b2 | |||
| 1f296403da | |||
| 35da7bdb44 | |||
| ab21dbad08 | |||
| c32c0d5674 | |||
| e506ccf4e1 | |||
| 0ef971b82b | |||
| b062de1133 | |||
| 3740380a7a | |||
| cb434793d5 | |||
| 9114f80b68 | |||
| ae3cfff380 | |||
| c046419acd | |||
| bd22bed10a | |||
| a0fead1880 | |||
| f7cd9865f4 | |||
| ebe8052d55 | |||
| 6b3c299a50 | |||
| 722778c74a | |||
| 1cd77e2a15 | |||
| 5be9473136 | |||
| 7553b76f15 | |||
| d78eda8aeb | |||
| 061063257a | |||
| 4e43ba544b | |||
| ccded10d86 | |||
| 2433feab09 | |||
| be04aca037 | |||
| 153680a5e6 | |||
| a15d023b45 | |||
| 63b8ae085a | |||
| 1c6e131746 | |||
| 00984781af | |||
| e1fb19f4e1 | |||
| 21cca695e5 | |||
| ba2bac17de | |||
| 5918e2fa9c | |||
| 6d94c92d97 | |||
| 3f0462510e | |||
| 40fa8afce4 | |||
| aac2de9221 | |||
| cbab6fa59f | |||
| b7b2a25953 | |||
| d9b54a524d | |||
| 9008e08171 | |||
| eb0990b37e | |||
| 1fc6de0403 | |||
| b467f2c858 | |||
| e211c09065 | |||
| f88f69e700 | |||
| eda6268d9d | |||
| 668207d59d | |||
| 803b336354 | |||
| 4c154d3cab | |||
| 7ad191c912 | |||
| 70cb81b4b5 | |||
| 6e516b7281 | |||
| aab05c4da9 | |||
| 562747ef41 | |||
| c1d2c36f32 | |||
| e8b9c6d5ff | |||
| b2b195e2cf | |||
| 2c559aa8c8 | |||
| bf90a2ddb6 | |||
| a3f155220b | |||
| 6d4faa6c52 | |||
| d8ecc76d4c | |||
| 05bcc4028d | |||
| 334a294e2a | |||
| 99f7142e3f | |||
| aa54518e2e | |||
| c2dab9c200 | |||
| 609f91e1b4 | |||
| 87e7258c9a | |||
| 134e79c0fd | |||
| 08fb61316d | |||
| 4b89069cab | |||
| 5f2d88f74a | |||
| 53692a79e2 | |||
| b07a7be262 | |||
| 7a42ff16ac | |||
| f848e5081d | |||
| 91a53a36ec | |||
| 1247d2085b | |||
| 90636f66a8 | |||
| c33df5977a | |||
| 6f69b7b752 | |||
| 912d349366 | |||
| 284f98f12a | |||
| 907febd86e | |||
| af7203b839 | |||
| a251d6a6cc | |||
| 449337a544 | |||
| f92f295055 | |||
| 6a4bc3e39f | |||
| 88e0dcfa06 | |||
| bd05b046d0 | |||
| 7e5215b5d4 | |||
| ba946c08dd | |||
| 3eda5144ae | |||
| e68f2f0a5f | |||
| 45d9b0cb2d | |||
| 66b4499973 | |||
| e035477e6a | |||
| 479b4c1b84 | |||
| 05a3f3ad8d | |||
| b67da6c3f8 | |||
| 0485f15998 | |||
| b60a7a2e07 | |||
| e6425ee41f | |||
| 0a17e41755 | |||
| 055c343ce0 | |||
| 3f68ccadd9 | |||
| 4e3227441b | |||
| e56cfb8173 | |||
| 66a5bb7c22 | |||
| 82bcef037d | |||
| 5ddf8245dd | |||
| 3e5aca86d5 | |||
| d7e0776148 | |||
| 416004b1bc | |||
| 2182287d3e | |||
| e3298061d2 | |||
| 9aafa1c6b2 | |||
| b72cca5403 | |||
| d0f13b5beb | |||
| 4504ab8bc2 | |||
| 7730e76c06 | |||
| dbfa049e1e | |||
| 9f05f28727 | |||
| a9da123259 | |||
| 001d676dec | |||
| 061b2c91a0 |
+9
-3
@@ -1,7 +1,13 @@
|
||||
.springBeans
|
||||
.DS_Store
|
||||
target
|
||||
integration-repo
|
||||
ivy-cache
|
||||
spring-build
|
||||
jmx.log
|
||||
.springBeans
|
||||
.DS_Store
|
||||
jxl.log
|
||||
jmx.log
|
||||
org.springframework.jdbc/derby.log
|
||||
org.springframework.spring-parent/.classpath
|
||||
org.springframework.spring-parent/.project
|
||||
org.springframework.test/test-output/
|
||||
spring-build/lib/docbook
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
<!-- Main targets -->
|
||||
<target name="publish-documentation" depends="publish-documentation.init">
|
||||
<sshexec host="spring02.managed.contegix.com" username="${username}" keyfile="${key.file}" passphrase="${passphrase}"
|
||||
<sshexec host="static.springsource.org" username="${username}" keyfile="${key.file}" passphrase="${passphrase}"
|
||||
command="mkdir /opt/www/domains/springframework.org/www/htdocs/spring/docs/${bundle.version}"/>
|
||||
|
||||
<scp remoteToDir="${username}@spring02.managed.contegix.com:/opt/www/domains/springframework.org/www/htdocs/spring/docs/${bundle.version}"
|
||||
<scp remoteToDir="${username}@static.springsource.org:/opt/www/domains/springframework.org/www/htdocs/spring/docs/${bundle.version}"
|
||||
keyfile="${key.file}" passphrase="${passphrase}" sftp="true" verbose="true">
|
||||
<fileset dir="${package.output.dir}">
|
||||
<include name="changelog.txt" />
|
||||
@@ -16,7 +16,7 @@
|
||||
<fileset dir="${package.docs.dir}" />
|
||||
</scp>
|
||||
|
||||
<sshexec host="spring02.managed.contegix.com" username="${username}" keyfile="${key.file}" passphrase="${passphrase}"
|
||||
<sshexec host="static.springsource.org" username="${username}" keyfile="${key.file}" passphrase="${passphrase}"
|
||||
command="rm /opt/www/domains/springframework.org/www/htdocs/spring/docs/3.0.x ; ln -s /opt/www/domains/springframework.org/www/htdocs/spring/docs/${bundle.version} /opt/www/domains/springframework.org/www/htdocs/spring/docs/3.0.x"/>
|
||||
</target>
|
||||
|
||||
|
||||
@@ -3,7 +3,144 @@ SPRING FRAMEWORK CHANGELOG
|
||||
http://www.springsource.org
|
||||
|
||||
|
||||
Changes in version 3.0.4 (2010-08-18)
|
||||
Changes in version 3.0.7 (2011-12-22)
|
||||
-------------------------------------
|
||||
|
||||
* fixed GenericTypeResolver to consistently return null if not resolvable
|
||||
* added proper "contentLength()" implementation to ByteArrayResource
|
||||
* refined Resource "exists()" check for HTTP URLs to always return false for 404 status
|
||||
* LocaleEditor and StringToLocaleConverter do not restrict variant part through validation
|
||||
* LinkedCaseInsensitiveMap overrides putAll method as well (for IBM JDK 1.6 compatibility)
|
||||
* ConversionService prevents Converter from trying to convert to a subtype of its actual target type
|
||||
* ConversionService is able to work with "Collections.emptyList()" as target type (again)
|
||||
* CollectionCollection/MapToMapConverter preserve original Collection/Map if no converted elements
|
||||
* fixed nested element conversion with a DataBinder + ConversionService + PropertyEditor
|
||||
* restored DataBinder's ability to bind to an auto-growing List with unknown element type
|
||||
* optimized DefaultListableBeanFactory's PropertyDescriptor caching for concurrent access
|
||||
* context:property-placeholder's "file-encoding" attribute value is being applied correctly
|
||||
* SpringValidatorAdapter accepts non-indexed set paths (for Hibernate Validator compatibility)
|
||||
* fixed AbstractAsyncExecutionAspect's setExecutor method to correctly wrap in a TaskExecutorAdapter
|
||||
* @Transactional qualifiers match against transaction manager definitions in parent contexts as well
|
||||
* TransactionSynchronizationManager eagerly cleans up void ResourceHolders on any access
|
||||
* updated H2 error codes in sql-error-codes.xml
|
||||
* fixed NamedParameterJdbcTemplate to use correct maximum type for queryForInt/Long
|
||||
* SimpleJdbcTestUtils executeSqlScript properly closes its LineNumberReader after use
|
||||
* Hibernate synchronization properly unbinds Session even in case of afterCompletion exception
|
||||
* JDO PersistenceManager synchronization performs close attempt after completion (if necessary)
|
||||
* JPA EntityManagerFactoryUtils silently ignores IllegalArgumentExceptions from setHint calls
|
||||
* added "forwarder" property to ConnectorServerFactoryBean, accepting an MBeanServerForwarder
|
||||
* JmsInvokerClientInterceptor/FactoryBean always uses createConnection/createSession when on JMS 1.1
|
||||
* RmiClientInterceptor detects nested SocketException as connect failure as well
|
||||
* Servlet/PortletContextResource's getFile prefers "file:" URL resolution over calling getRealPath
|
||||
* Portlet session mutex uses global session attribute to be shared among all portlets in the session
|
||||
* fixed ServletServerHttpRequest to reconstruct from "request.getParameterMap()" for form POST only
|
||||
* fixed @RequestMapping header matching to correctly process negated header conditions
|
||||
* added "getObjectMapper()" accessor to MappingJacksonHttpMessageConverter
|
||||
* ResourceHttpRequestHandler sends content without content-type header if no media type found
|
||||
* AbstractCachingViewResolver allows for caching unresolved view names ("cacheUnresolved"=true)
|
||||
* fixed "formMultiSelect"/"formCheckboxes" FreeMarker macros to compare against actual field value
|
||||
|
||||
|
||||
Changes in version 3.0.6 (2011-08-18)
|
||||
-------------------------------------
|
||||
|
||||
* fixed aspects bundle to declare dependencies for @Async aspect as well
|
||||
* ProxyCreationContext uses "ThreadLocal.remove()" over "ThreadLocal.set(null)" as well
|
||||
* DefaultListableBeanFactory is only deserializable through a SerializedBeanFactoryReference
|
||||
* DefaultListableBeanFactory's getBean(name, type) attempts type conversion if necessary
|
||||
* DefaultListableBeanFactory allows for init methods to register further bean definitions (again)
|
||||
* XmlBeanDefinitionReader accepts description subelement within map entry as well (as per the XSD)
|
||||
* ConfigurationClassPostProcessor supports use of same processor instance with several factories
|
||||
* fixed potential InjectionMetadata NPE when using SpringBeanAutowiringInterceptor
|
||||
* SpringBeanAutowiringSupport is able to process @Value annotations on any given target instance
|
||||
* overridden @PersistenceContext annotations on subclass methods are being processed correctly
|
||||
* BeanDefinitionVisitor now actually visits factory method names
|
||||
* restored support for String-to-ContextResource conversion
|
||||
* restored original GenericConversionService behavior with respect to empty collections/maps
|
||||
* restored original FormattingConversionService behavior with respect to the use of subtypes
|
||||
* added "formatters" property to FormattingConversionServiceFactoryBean
|
||||
* collection/array conversion returns original collection if possible (instead of first element)
|
||||
* fixed collection element resolution when using a ConversionService with a DataBinder
|
||||
* DataBinder uses a default limit of 256 for array/collection auto-growing
|
||||
* added "autoGrowNestedPaths" property to ConfigurableWebBindingInitializer
|
||||
* Servlet/PortletRequestDataBinder perform unwrapping for MultipartRequest as well
|
||||
* fixed AbstractBindingResult to avoid NPE in "hashCode()" if target is null
|
||||
* fixed several HttpHeaders issues (charset handling, quoting/unquoting)
|
||||
* SimpleClientHttpRequest uses fixed-length streaming mode (always sets content-length header)
|
||||
* added "connectTimeout" and "readTimeout" properties to Simple/CommonsClientHttpRequestFactory
|
||||
* explicit status code in RedirectView respected in HTTP 1.0 compatibility mode
|
||||
* FormHttpMessageConverter correctly processes POST requests
|
||||
* ResourceHttpRequestHandler does not set Content-Length header for 304 response
|
||||
* ResourceHttpRequestHandler detects invalid directory traversal in given path
|
||||
* LocaleChangeInterceptor validates locale values in order to prevent XSS vulnerability
|
||||
* HtmlUtils properly escapes single quotes as well
|
||||
* added support for web.xml context-param "springJspExpressionSupport" (explicit "true"/"false")
|
||||
* ContextLoader and FrameworkServlet support "contextId" parameter for custom serialization id
|
||||
* RemoteExporter uses an opaque proxy for 'serviceInterface' (no AOP interfaces exposed)
|
||||
* added "acceptProxyClasses" flag to RemoteInvocationSerializingExporter
|
||||
* refined WebLogic RMI descriptor to only mark 'getTargetInterfaceName' method as idempotent
|
||||
* EhCacheManagerFactoryBean properly closes "ehcache.xml" input stream, if any
|
||||
* revised JMS CachedConnectionFactory to avoid unnecessary rollback calls on Session return
|
||||
* fixed JMS CachedConnectionFactory to fully synchronize its Session list
|
||||
* fixed NamedParameterJdbcTemplate's handling of arrays as query parameters
|
||||
* fixed JPA 2.0 timeout hints to correctly specify milliseconds
|
||||
* updated Quartz package to support Quartz 1.8 as well (note: not supporting Quartz 2.0 yet)
|
||||
* fixed @Rule execution order in SpringJUnit4ClassRunner to match standard JUnit 4 behavior
|
||||
|
||||
|
||||
Changes in version 3.0.5 (2010-10-20)
|
||||
-------------------------------------
|
||||
|
||||
* support for Hibernate 3.6 final
|
||||
* added core serializer abstraction with default implementations using Java Serialization
|
||||
* consistent use of JDK 1.5's "ThreadLocal.remove()" over "ThreadLocal.set(null)"
|
||||
* fixed JodaTimeContextHolder to use a non-inheritable ThreadLocal and expose a reset method
|
||||
* revised "ClassUtils.isAssignable" semantics to cover primitives vs wrappers in both directions
|
||||
* optimized AnnotationUtils findAnnotation performance for repeated search on same interfaces
|
||||
* ConversionService protects itself against infinite recursion in ObjectToCollectionConverter
|
||||
* fixed TypeDescriptor to correctly resolve nested collections and their element types
|
||||
* BeanWrapper does not attempt to populate Map values on access (just auto-grows Map itself)
|
||||
* fixed Autowired/CommonAnnotationBeanPostProcessor to prevent race condition in skipping check
|
||||
* fixed @Value injection to correctly cache temporary null results for non-singleton beans
|
||||
* ApplicationContext registers context-specific ClassArrayEditor for its bean ClassLoader
|
||||
* refined ApplicationContext singleton processing to not fail for manually registered null instances
|
||||
* fixed ApplicationContext event processing for repeated invocations to non-singleton listener beans
|
||||
* optimized @Bean error messages for static factory methods as well as for argument type mismatches
|
||||
* modified expression parsing to pass full TypeDescriptor context through to ConversionService calls
|
||||
* adapted expression parser's Constructor/MethodResolver to accept TypeDescriptors instead of raw types
|
||||
* SpEL supports projection on any kind of Collection (not just on Lists and arrays)
|
||||
* SpEL MapAccessor consistently rejects "target.key" style access to Maps if no such key is found
|
||||
* SpEL method invocations prefer method with fewest parameters (e.g. no-arg over vararg)
|
||||
* AspectJExpressionPointcut uses bean ClassLoader for initializing the AspectJ pointcut parser
|
||||
* added AnnotationAsyncExecutionAspect as AspectJ-based variant of @Async processing
|
||||
* added mode="proxy"/"aspectj" and proxy-target-class options to task:annotation-driven
|
||||
* JDBC bundle uses local ClassLoader as bean ClassLoader for "sql-error-codes.xml" parsing
|
||||
* EmbeddedDatabaseFactory shuts down database when failing to populate it in "initDatabase()"
|
||||
* embedded database support now also works with Derby >= 10.6
|
||||
* "jdbc:embedded-database" uses id as database name to allow multiple ones in parallel
|
||||
* ResourceDatabasePopulator throws descriptive ScriptStatementFailedException with resource details
|
||||
* added configurable Connection/Statement/ResultSet target types to Jdbc4NativeJdbcExtractor
|
||||
* added OracleJdbc4NativeJdbcExtractor with pre-configured Oracle JDBC API types
|
||||
* DefaultLobHandler's "wrapAsLob" mode works with PostgreSQL's "getAsciiStream()" requirement
|
||||
* ResultSetWrappingSqlRowSet (as used by JdbcTemplate's "queryForRowSet") supports column labels now
|
||||
* LocalSessionFactoryBean's "entityCacheStrategies" works with region names on Hibernate 3.6 as well
|
||||
* fixed DefaultMessageListenerContainer's no-message-received commit to work without Session caching
|
||||
* DefaultMessageListenerContainer's skips no-message-received commit on Tibco (avoiding a deadlock)
|
||||
* JaxWsPortClientInterceptor does not fall back to annotation-specified name as portName anymore
|
||||
* UriTemplate is serializable now
|
||||
* fixed AnnotationMethodHandlerAdapter's caching to avoid concurrency issues in RequestMappingInfo
|
||||
* fixed @MVC processing of parameter-level annotations to work with interface-based proxies again
|
||||
* revised @RequestParam processing to support CSV-to-array/collection binding with ConversionService
|
||||
* fixed EvalTag's EvaluationContext caching to properly handle JSP tag caching across requests
|
||||
* AbstractJasperReportsView only sets locale model attributes if not present already
|
||||
* DispatcherPortlet throws custom NoHandlerFoundException instead of misleading UnavailableException
|
||||
* DispatcherPortlet copies all action parameters to render parameters in case of an action exception
|
||||
* DispatcherPortlet's default resource serving explicitly prevents access to WEB-INF and META-INF
|
||||
* Portlet @ExceptionHandler methods allow for writing the response directly (like in the Servlet case)
|
||||
* MockHttpServletRequest/HttpSession/etc returns independent Enumeration from "getAttributeNames()"
|
||||
|
||||
|
||||
Changes in version 3.0.4 (2010-08-19)
|
||||
-------------------------------------
|
||||
|
||||
* support for Hibernate Core 3.6, Hibernate Validator 4.1, EclipseLink 2.1, EHCache 2.2
|
||||
@@ -17,7 +154,7 @@ Changes in version 3.0.4 (2010-08-18)
|
||||
* fixed double ConversionFailedException nesting for ObjectToObjectConverter invocations
|
||||
* BeanWrapper preserves annotation information for individual array/list/map elements
|
||||
* Spring's constructor resolution consistently finds non-public multi-arg constructors
|
||||
* revised constructor argument caching for highly concurrent creation scenarios
|
||||
* revised constructor argument caching, avoiding a race condition for converted argument values
|
||||
* SpEL passes full collection type context (generics, annotations) to ConversionService
|
||||
* SpEL 'select last' operator now works consistently with maps
|
||||
* BeanWrapper/DataBinder's "autoGrowNestedPaths" works for Maps as well
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
SPRING FRAMEWORK 3.0.4 (August 2010)
|
||||
------------------------------------
|
||||
http://www.springframework.org
|
||||
SPRING FRAMEWORK 3.0.7 (December 2011)
|
||||
--------------------------------------
|
||||
http://www.springsource.org
|
||||
|
||||
1. INTRODUCTION
|
||||
|
||||
|
||||
+30
-29
@@ -1,29 +1,30 @@
|
||||
version=3.0.4
|
||||
# osgi ranges
|
||||
spring.osgi.range.nq=${version:[=.=.=, =.=.+1)}
|
||||
spring.osgi.range="${spring.osgi.range.nq}"
|
||||
aj.osgi.range="[1.5.4, 2.0.0)"
|
||||
|
||||
#
|
||||
release.type=integration
|
||||
natural.name=spring-framework
|
||||
project.name=Spring Framework
|
||||
project.key=SPR
|
||||
ivy.cache.dir=${basedir}/../ivy-cache
|
||||
integration.repo.dir=${basedir}/../integration-repo
|
||||
javadoc.exclude.package.names=org/springframework/samples/**
|
||||
javadoc.max.memory=256M
|
||||
test.vm.args=-Xmx1024M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError
|
||||
compiler.args=-enableJavadoc -warn:none
|
||||
|
||||
# For when releasing
|
||||
#release.type=release
|
||||
#build.stamp=RELEASE
|
||||
|
||||
# For when releasing milestones
|
||||
#release.type=milestone
|
||||
#build.stamp=M1
|
||||
|
||||
# For development in trunk
|
||||
#release.type=integration
|
||||
#build.stamp=BUILD-SNAPSHOT
|
||||
version=3.0.8
|
||||
# osgi ranges
|
||||
spring.osgi.range.nq=${version:[=.=.=, =.=.+1)}
|
||||
spring.osgi.range="${spring.osgi.range.nq}"
|
||||
aj.osgi.range="[1.5.4, 2.0.0)"
|
||||
|
||||
#
|
||||
#release.type=integration
|
||||
natural.name=spring-framework
|
||||
project.name=Spring Framework
|
||||
project.key=SPR
|
||||
ivy.cache.dir=${basedir}/../ivy-cache
|
||||
integration.repo.dir=${basedir}/../integration-repo
|
||||
license.dir=${basedir}/../build-spring-framework/resources
|
||||
javadoc.exclude.package.names=org/springframework/samples/**
|
||||
javadoc.max.memory=256M
|
||||
test.vm.args=-Xmx1024M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError
|
||||
compiler.args=-enableJavadoc -warn:none
|
||||
|
||||
# For when releasing
|
||||
#release.type=release
|
||||
#build.stamp=RELEASE
|
||||
|
||||
# For when releasing milestones
|
||||
#release.type=milestone
|
||||
#build.stamp=M1
|
||||
|
||||
# For development in trunk
|
||||
release.type=integration
|
||||
build.stamp=BUILD-SNAPSHOT
|
||||
|
||||
+5
-6
@@ -1,6 +1,5 @@
|
||||
#common dependency versions
|
||||
aspectj.version=1.6.8.RELEASE
|
||||
commons.pool.version=1.5.3
|
||||
slf4j.version=1.5.6
|
||||
org.testng.version=5.10.0
|
||||
org.junit.version=4.7.0
|
||||
#common dependency versions
|
||||
aspectj.version=1.6.8.RELEASE
|
||||
slf4j.version=1.5.3
|
||||
junit.version=4.7.0
|
||||
testng.version=5.10.0
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
<publications>
|
||||
<artifact name="${ant.project.name}"/>
|
||||
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
|
||||
<artifact name="license" type="license" ext="txt"/>
|
||||
<artifact name="notice" type="notice" ext="txt"/>
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
@@ -28,14 +30,14 @@
|
||||
<dependency org="net.sourceforge.cglib" name="com.springsource.net.sf.cglib" rev="2.2.0" conf="optional, bytecode-proxy->compile"/>
|
||||
<dependency org="org.aopalliance" name="com.springsource.org.aopalliance" rev="1.0.0" conf="compile->compile"/>
|
||||
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.logging" rev="1.1.1" conf="compile, commons-logging->compile"/>
|
||||
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.pool" rev="${commons.pool.version}" conf="optional, pooling->compile"/>
|
||||
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.pool" rev="1.5.3" conf="optional, pooling->compile"/>
|
||||
<dependency org="org.aspectj" name="com.springsource.org.aspectj.weaver" rev="${aspectj.version}" conf="optional, aspectj->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.beans" rev="latest.integration" conf="compile->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.core" rev="latest.integration" conf="compile->compile"/>
|
||||
<!-- test dependencies -->
|
||||
<dependency org="org.apache.log4j" name="com.springsource.org.apache.log4j" rev="1.2.15" conf="test->runtime"/>
|
||||
<dependency org="org.easymock" name="com.springsource.org.easymock" rev="2.5.1" conf="test->compile"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${org.junit.version}" conf="test->runtime"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->runtime"/>
|
||||
<dependency org="org.springframework" name="org.springframework.asm" rev="latest.integration" conf="test->runtime"/>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.0.4.BUILD-SNAPSHOT</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.0.4.BUILD-SNAPSHOT</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
+25
-21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author 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,7 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -95,12 +96,6 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AspectJExpressionPointcut.class);
|
||||
|
||||
private transient PointcutParser pointcutParser;
|
||||
|
||||
private transient PointcutExpression pointcutExpression;
|
||||
|
||||
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||
|
||||
private Class pointcutDeclarationScope;
|
||||
|
||||
private String[] pointcutParameterNames = new String[0];
|
||||
@@ -109,12 +104,15 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private transient PointcutExpression pointcutExpression;
|
||||
|
||||
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||
|
||||
|
||||
/**
|
||||
* Create a new default AspectJExpressionPointcut.
|
||||
*/
|
||||
public AspectJExpressionPointcut() {
|
||||
initializePointcutParser();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +122,6 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
* @param paramTypes the parameter types for the pointcut
|
||||
*/
|
||||
public AspectJExpressionPointcut(Class declarationScope, String[] paramNames, Class[] paramTypes) {
|
||||
initializePointcutParser();
|
||||
this.pointcutDeclarationScope = declarationScope;
|
||||
if (paramNames.length != paramTypes.length) {
|
||||
throw new IllegalStateException(
|
||||
@@ -134,13 +131,6 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
this.pointcutParameterTypes = paramTypes;
|
||||
}
|
||||
|
||||
private void initializePointcutParser() {
|
||||
this.pointcutParser =
|
||||
PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(
|
||||
SUPPORTED_PRIMITIVES);
|
||||
this.pointcutParser.registerPointcutDesignatorHandler(new BeanNamePointcutDesignatorHandler());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the declaration scope for the pointcut.
|
||||
@@ -196,15 +186,30 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
private PointcutExpression buildPointcutExpression() {
|
||||
PointcutParser parser = initializePointcutParser();
|
||||
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
|
||||
for (int i = 0; i < pointcutParameters.length; i++) {
|
||||
pointcutParameters[i] = this.pointcutParser.createPointcutParameter(
|
||||
pointcutParameters[i] = parser.createPointcutParameter(
|
||||
this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
|
||||
}
|
||||
return this.pointcutParser.parsePointcutExpression(
|
||||
return parser.parsePointcutExpression(
|
||||
replaceBooleanOperators(getExpression()), this.pointcutDeclarationScope, pointcutParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the underlying AspectJ pointcut parser.
|
||||
*/
|
||||
private PointcutParser initializePointcutParser() {
|
||||
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
|
||||
Thread.currentThread().getContextClassLoader());
|
||||
PointcutParser parser =
|
||||
PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
|
||||
SUPPORTED_PRIMITIVES, cl);
|
||||
parser.registerPointcutDesignatorHandler(new BeanNamePointcutDesignatorHandler());
|
||||
return parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a pointcut expression has been specified in XML, the user cannot
|
||||
* write <code>and</code> as "&&" (though && will work).
|
||||
@@ -218,6 +223,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
@@ -226,7 +232,6 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
return this.pointcutExpression;
|
||||
}
|
||||
|
||||
|
||||
public boolean matches(Class targetClass) {
|
||||
checkReadyToMatch();
|
||||
try {
|
||||
@@ -455,7 +460,6 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
/**
|
||||
* Matcher class for the BeanNamePointcutDesignatorHandler.
|
||||
*
|
||||
* <p>Dynamic match tests for this matcher always return true,
|
||||
* since the matching decision is made at the proxy creation time.
|
||||
* For static match tests, this matcher abstains to allow the overall
|
||||
@@ -535,7 +539,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
ois.defaultReadObject();
|
||||
|
||||
// Initialize transient fields.
|
||||
initializePointcutParser();
|
||||
// pointcutExpression will be initialized lazily by checkReadyToMatch()
|
||||
this.shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -76,7 +76,12 @@ public abstract class AopContext {
|
||||
*/
|
||||
static Object setCurrentProxy(Object proxy) {
|
||||
Object old = currentProxy.get();
|
||||
currentProxy.set(proxy);
|
||||
if (proxy != null) {
|
||||
currentProxy.set(proxy);
|
||||
}
|
||||
else {
|
||||
currentProxy.remove();
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author 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,12 @@ public class ProxyCreationContext {
|
||||
* @param beanName the name of the bean, or <code>null</code> to reset it
|
||||
*/
|
||||
static void setCurrentProxiedBeanName(String beanName) {
|
||||
currentProxiedBeanName.set(beanName);
|
||||
if (beanName != null) {
|
||||
currentProxiedBeanName.set(beanName);
|
||||
}
|
||||
else {
|
||||
currentProxiedBeanName.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -70,8 +70,9 @@ public class ExposeInvocationInterceptor implements MethodInterceptor, Ordered,
|
||||
MethodInvocation mi = invocation.get();
|
||||
if (mi == null)
|
||||
throw new IllegalStateException(
|
||||
"No MethodInvocation found: Check that an AOP invocation is in progress, " +
|
||||
"and that the ExposeInvocationInterceptor is in the interceptor chain.");
|
||||
"No MethodInvocation found: Check that an AOP invocation is in progress, and that the " +
|
||||
"ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that " +
|
||||
"advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!");
|
||||
return mi;
|
||||
}
|
||||
|
||||
|
||||
+8
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package org.springframework.aop.target;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
@@ -91,6 +93,11 @@ public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFac
|
||||
// Serialization support
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||
throw new NotSerializableException("A prototype-based TargetSource itself is not deserializable - " +
|
||||
"just a disconnected SingletonTargetSource is");
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces this object with a SingletonTargetSource on serialization.
|
||||
* Protected as otherwise it won't be invoked for subclasses.
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -106,7 +106,7 @@ public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
|
||||
this.targetSet.clear();
|
||||
}
|
||||
// Clear ThreadLocal, just in case.
|
||||
this.targetInThread.set(null);
|
||||
this.targetInThread.remove();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<artifacts pattern="${jar.output.dir}/[artifact].[ext]"/>
|
||||
<artifacts pattern="${source-jar.output.dir}/[artifact].[ext]"/>
|
||||
<artifacts pattern="${ivy.output.dir}/[artifact].[ext]"/>
|
||||
<artifacts pattern="${license.dir}/[artifact].[ext]"/>
|
||||
</ivy:publish>
|
||||
</target>
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
<publications>
|
||||
<artifact name="${ant.project.name}"/>
|
||||
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
|
||||
<artifact name="license" type="license" ext="txt"/>
|
||||
<artifact name="notice" type="notice" ext="txt"/>
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-asm</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.0.4.BUILD-SNAPSHOT</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.0.4.BUILD-SNAPSHOT</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
<publications>
|
||||
<artifact name="${ant.project.name}"/>
|
||||
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
|
||||
<artifact name="license" type="license" ext="txt"/>
|
||||
<artifact name="notice" type="notice" ext="txt"/>
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
@@ -31,9 +33,9 @@
|
||||
<dependency org="org.springframework" name="org.springframework.test" rev="latest.integration" conf="test->runtime"/>
|
||||
<dependency org="org.springframework" name="org.springframework.context" rev="latest.integration" conf="test->runtime"/>
|
||||
<dependency org="org.springframework" name="org.springframework.context.support" rev="latest.integration" conf="test->runtime"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${org.junit.version}" conf="test->compile"/>
|
||||
<dependency org="javax.persistence" name="com.springsource.javax.persistence" rev="1.0.0" conf="provided->compile"/>
|
||||
<dependency org="javax.mail" name="com.springsource.javax.mail" rev="1.4.0" conf="test->compile"/>
|
||||
<dependency org="javax.persistence" name="com.springsource.javax.persistence" rev="1.0.0" conf="optional, orm->compile"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->compile"/>
|
||||
<dependency org="javax.mail" name="com.springsource.javax.mail" rev="1.4.0" conf="optional, test->compile"/>
|
||||
</dependencies>
|
||||
|
||||
</ivy-module>
|
||||
|
||||
@@ -1,84 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aspects</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.0.4.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.0.4.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<!-- common logging dependency is in spring-core -->
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.mail</groupId>
|
||||
<artifactId>mail</artifactId>
|
||||
<version>1.4</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<junitArtifactName>junit:junit</junitArtifactName>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aspects</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<!-- commons logging dependency is in spring-core -->
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-orm</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>1.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.mail</groupId>
|
||||
<artifactId>mail</artifactId>
|
||||
<version>1.4</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<junitArtifactName>junit:junit</junitArtifactName>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
+16
-1
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -12,7 +28,6 @@ import java.util.List;
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) {
|
||||
|
||||
|
||||
+26
-13
@@ -1,18 +1,33 @@
|
||||
package org.springframework.mock.staticmock;
|
||||
/*
|
||||
* Copyright 2002-2010 the original author 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.
|
||||
*/
|
||||
|
||||
import javax.persistence.Entity;
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
/**
|
||||
* Annotation-based aspect to use in test build to enable mocking static methods
|
||||
* on Entity classes, as used by Roo for finders.
|
||||
* <br>
|
||||
* Mocking will occur in the call stack of any method in a class (typically a test class)
|
||||
* on JPA-annotated <code>@Entity</code> classes, as used by Roo for finders.
|
||||
*
|
||||
* <p>Mocking will occur in the call stack of any method in a class (typically a test class)
|
||||
* that is annotated with the @MockStaticEntityMethods annotation.
|
||||
* <br>
|
||||
* Also provides static methods to simplify the programming model for
|
||||
*
|
||||
* <p>Also provides static methods to simplify the programming model for
|
||||
* entering playback mode and setting expected return values.
|
||||
* <br>
|
||||
* Usage:<ol>
|
||||
*
|
||||
* <p>Usage:
|
||||
* <ol>
|
||||
* <li>Annotate a test class with @MockStaticEntityMethods.
|
||||
* <li>In each test method, AnnotationDrivenStaticEntityMockingControl will begin in recording mode.
|
||||
* Invoke static methods on Entity classes, with each recording-mode invocation
|
||||
@@ -23,11 +38,9 @@ import javax.persistence.Entity;
|
||||
* occur automatically.
|
||||
* </ol>
|
||||
*
|
||||
* @see MockStaticEntityMethods
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @see MockStaticEntityMethods
|
||||
*/
|
||||
public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl {
|
||||
|
||||
@@ -50,6 +63,6 @@ public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodM
|
||||
// @MockStatics classes to invoke each other without resetting the mocking environment
|
||||
protected pointcut mockStaticsTestMethod() : execution(public * (@MockStaticEntityMethods *).*(..));
|
||||
|
||||
protected pointcut methodToMock() : execution(public static * (@Entity *).*(..));
|
||||
protected pointcut methodToMock() : execution(public static * (@javax.persistence.Entity *).*(..));
|
||||
|
||||
}
|
||||
|
||||
+17
-4
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
@@ -8,11 +23,9 @@ import java.lang.annotation.Target;
|
||||
/**
|
||||
* Annotation to indicate a test class for whose @Test methods
|
||||
* static methods on Entity classes should be mocked.
|
||||
*
|
||||
* @see AbstractMethodMockingControl
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @see AbstractMethodMockingControl
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author 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.scheduling.aspectj;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.core.task.support.TaskExecutorAdapter;
|
||||
|
||||
/**
|
||||
* Abstract aspect that routes selected methods asynchronously.
|
||||
*
|
||||
* <p>This aspect needs to be injected with an implementation of
|
||||
* {@link Executor} to activate it for a specific thread pool.
|
||||
* Otherwise it will simply delegate all calls synchronously.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0.5
|
||||
*/
|
||||
public abstract aspect AbstractAsyncExecutionAspect {
|
||||
|
||||
private AsyncTaskExecutor asyncExecutor;
|
||||
|
||||
public void setExecutor(Executor executor) {
|
||||
if (executor instanceof AsyncTaskExecutor) {
|
||||
this.asyncExecutor = (AsyncTaskExecutor) executor;
|
||||
}
|
||||
else {
|
||||
this.asyncExecutor = new TaskExecutorAdapter(executor);
|
||||
}
|
||||
}
|
||||
|
||||
Object around() : asyncMethod() {
|
||||
if (this.asyncExecutor == null) {
|
||||
return proceed();
|
||||
}
|
||||
Callable<Object> callable = new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
Object result = proceed();
|
||||
if (result instanceof Future) {
|
||||
return ((Future<?>) result).get();
|
||||
}
|
||||
return null;
|
||||
}};
|
||||
Future<?> result = this.asyncExecutor.submit(callable);
|
||||
if (Future.class.isAssignableFrom(((MethodSignature) thisJoinPointStaticPart.getSignature()).getReturnType())) {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract pointcut asyncMethod();
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author 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.scheduling.aspectj;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
/**
|
||||
* Aspect to route methods based on the {@link Async} annotation.
|
||||
*
|
||||
* <p>This aspect routes methods marked with the {@link Async} annotation
|
||||
* as well as methods in classes marked with the same. Any method expected
|
||||
* to be routed asynchronously must return either void, {@link Future},
|
||||
* or a subtype of {@link Future}. This aspect, therefore, will produce
|
||||
* a compile-time error for methods that violate this constraint on the return type.
|
||||
* If, however, a class marked with <code>@Async</code> contains a method that
|
||||
* violates this constraint, it produces only a warning.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
* @since 3.0.5
|
||||
*/
|
||||
public aspect AnnotationAsyncExecutionAspect extends AbstractAsyncExecutionAspect {
|
||||
|
||||
private pointcut asyncMarkedMethod()
|
||||
: execution(@Async (void || Future+) *(..));
|
||||
|
||||
private pointcut asyncTypeMarkedMethod()
|
||||
: execution((void || Future+) (@Async *).*(..));
|
||||
|
||||
public pointcut asyncMethod() : asyncMarkedMethod() || asyncTypeMarkedMethod();
|
||||
|
||||
declare error:
|
||||
execution(@Async !(void||Future) *(..)):
|
||||
"Only methods that return void or Future may have an @Async annotation";
|
||||
|
||||
declare warning:
|
||||
execution(!(void||Future) (@Async *).*(..)):
|
||||
"Methods in a class marked with @Async that do not return void or Future will be routed synchronously";
|
||||
|
||||
}
|
||||
+93
-93
@@ -1,93 +1,93 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author 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.transaction.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aspectj.lang.annotation.SuppressAjWarnings;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
import org.springframework.transaction.interceptor.TransactionAttributeSource;
|
||||
|
||||
/**
|
||||
* Abstract superaspect for AspectJ transaction aspects. Concrete
|
||||
* subaspects will implement the <code>transactionalMethodExecution()</code>
|
||||
* pointcut using a strategy such as Java 5 annotations.
|
||||
*
|
||||
* <p>Suitable for use inside or outside the Spring IoC container.
|
||||
* Set the "transactionManager" property appropriately, allowing
|
||||
* use of any transaction implementation supported by Spring.
|
||||
*
|
||||
* <p><b>NB:</b> If a method implements an interface that is itself
|
||||
* transactionally annotated, the relevant Spring transaction attribute
|
||||
* will <i>not</i> be resolved. This behavior will vary from that of Spring AOP
|
||||
* if proxying an interface (but not when proxying a class). We recommend that
|
||||
* transaction annotations should be added to classes, rather than business
|
||||
* interfaces, as they are an implementation detail rather than a contract
|
||||
* specification validation.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract aspect AbstractTransactionAspect extends TransactionAspectSupport {
|
||||
|
||||
/**
|
||||
* Construct object using the given transaction metadata retrieval strategy.
|
||||
* @param tas TransactionAttributeSource implementation, retrieving Spring
|
||||
* transaction metadata for each joinpoint. Write the subclass to pass in null
|
||||
* if it's intended to be configured by Setter Injection.
|
||||
*/
|
||||
protected AbstractTransactionAspect(TransactionAttributeSource tas) {
|
||||
setTransactionAttributeSource(tas);
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
before(Object txObject) : transactionalMethodExecution(txObject) {
|
||||
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
TransactionInfo txInfo = createTransactionIfNecessary(method, txObject.getClass());
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) throwing(Throwable t) : transactionalMethodExecution(txObject) {
|
||||
try {
|
||||
completeTransactionAfterThrowing(TransactionAspectSupport.currentTransactionInfo(), t);
|
||||
}
|
||||
catch (Throwable t2) {
|
||||
logger.error("Failed to close transaction after throwing in a transactional method", t2);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) returning() : transactionalMethodExecution(txObject) {
|
||||
commitTransactionAfterReturning(TransactionAspectSupport.currentTransactionInfo());
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) : transactionalMethodExecution(txObject) {
|
||||
cleanupTransactionInfo(TransactionAspectSupport.currentTransactionInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete subaspects must implement this pointcut, to identify
|
||||
* transactional methods. For each selected joinpoint, TransactionMetadata
|
||||
* will be retrieved using Spring's TransactionAttributeSource interface.
|
||||
*/
|
||||
protected abstract pointcut transactionalMethodExecution(Object txObject);
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 the original author 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.transaction.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aspectj.lang.annotation.SuppressAjWarnings;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
import org.springframework.transaction.interceptor.TransactionAttributeSource;
|
||||
|
||||
/**
|
||||
* Abstract superaspect for AspectJ transaction aspects. Concrete
|
||||
* subaspects will implement the <code>transactionalMethodExecution()</code>
|
||||
* pointcut using a strategy such as Java 5 annotations.
|
||||
*
|
||||
* <p>Suitable for use inside or outside the Spring IoC container.
|
||||
* Set the "transactionManager" property appropriately, allowing
|
||||
* use of any transaction implementation supported by Spring.
|
||||
*
|
||||
* <p><b>NB:</b> If a method implements an interface that is itself
|
||||
* transactionally annotated, the relevant Spring transaction attribute
|
||||
* will <i>not</i> be resolved. This behavior will vary from that of Spring AOP
|
||||
* if proxying an interface (but not when proxying a class). We recommend that
|
||||
* transaction annotations should be added to classes, rather than business
|
||||
* interfaces, as they are an implementation detail rather than a contract
|
||||
* specification validation.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract aspect AbstractTransactionAspect extends TransactionAspectSupport {
|
||||
|
||||
/**
|
||||
* Construct object using the given transaction metadata retrieval strategy.
|
||||
* @param tas TransactionAttributeSource implementation, retrieving Spring
|
||||
* transaction metadata for each joinpoint. Write the subclass to pass in null
|
||||
* if it's intended to be configured by Setter Injection.
|
||||
*/
|
||||
protected AbstractTransactionAspect(TransactionAttributeSource tas) {
|
||||
setTransactionAttributeSource(tas);
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
before(Object txObject) : transactionalMethodExecution(txObject) {
|
||||
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
TransactionInfo txInfo = createTransactionIfNecessary(method, txObject.getClass());
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) throwing(Throwable t) : transactionalMethodExecution(txObject) {
|
||||
try {
|
||||
completeTransactionAfterThrowing(TransactionAspectSupport.currentTransactionInfo(), t);
|
||||
}
|
||||
catch (Throwable t2) {
|
||||
logger.error("Failed to close transaction after throwing in a transactional method", t2);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) returning() : transactionalMethodExecution(txObject) {
|
||||
commitTransactionAfterReturning(TransactionAspectSupport.currentTransactionInfo());
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) : transactionalMethodExecution(txObject) {
|
||||
cleanupTransactionInfo(TransactionAspectSupport.currentTransactionInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete subaspects must implement this pointcut, to identify
|
||||
* transactional methods. For each selected joinpoint, TransactionMetadata
|
||||
* will be retrieved using Spring's TransactionAttributeSource interface.
|
||||
*/
|
||||
protected abstract pointcut transactionalMethodExecution(Object txObject);
|
||||
|
||||
}
|
||||
|
||||
+75
-76
@@ -1,76 +1,75 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Concrete AspectJ transaction aspect using Spring Transactional annotation
|
||||
* for JDK 1.5+.
|
||||
*
|
||||
* <p>When using this aspect, you <i>must</i> annotate the implementation class
|
||||
* (and/or methods within that class), <i>not</i> the interface (if any) that
|
||||
* the class implements. AspectJ follows Java's rule that annotations on
|
||||
* interfaces are <i>not</i> inherited.
|
||||
*
|
||||
* <p>A @Transactional annotation on a class specifies the default transaction
|
||||
* semantics for the execution of any <b>public</b> operation in the class.
|
||||
*
|
||||
* <p>A @Transactional annotation on a method within the class overrides the
|
||||
* default transaction semantics given by the class annotation (if present).
|
||||
* Any method may be annotated (regardless of visibility).
|
||||
* Annotating non-public methods directly is the only way
|
||||
* to get transaction demarcation for the execution of such operations.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
* @see org.springframework.transaction.annotation.Transactional
|
||||
*/
|
||||
public aspect AnnotationTransactionAspect extends AbstractTransactionAspect {
|
||||
|
||||
public AnnotationTransactionAspect() {
|
||||
super(new AnnotationTransactionAttributeSource(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the execution of any public method in a type with the
|
||||
* Transactional annotation, or any subtype of a type with the
|
||||
* Transactional annotation.
|
||||
*/
|
||||
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
|
||||
execution(public * ((@Transactional *)+).*(..)) && @this(Transactional);
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the
|
||||
* Transactional annotation.
|
||||
*/
|
||||
private pointcut executionOfTransactionalMethod() :
|
||||
execution(* *(..)) && @annotation(Transactional);
|
||||
|
||||
/**
|
||||
* Definition of pointcut from super aspect - matched join points
|
||||
* will have Spring transaction management applied.
|
||||
*/
|
||||
protected pointcut transactionalMethodExecution(Object txObject) :
|
||||
(executionOfAnyPublicMethodInAtTransactionalType()
|
||||
|| executionOfTransactionalMethod() )
|
||||
&& this(txObject);
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 the original author 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.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Concrete AspectJ transaction aspect using Spring's @Transactional annotation.
|
||||
*
|
||||
* <p>When using this aspect, you <i>must</i> annotate the implementation class
|
||||
* (and/or methods within that class), <i>not</i> the interface (if any) that
|
||||
* the class implements. AspectJ follows Java's rule that annotations on
|
||||
* interfaces are <i>not</i> inherited.
|
||||
*
|
||||
* <p>A @Transactional annotation on a class specifies the default transaction
|
||||
* semantics for the execution of any <b>public</b> operation in the class.
|
||||
*
|
||||
* <p>A @Transactional annotation on a method within the class overrides the
|
||||
* default transaction semantics given by the class annotation (if present).
|
||||
* Any method may be annotated (regardless of visibility).
|
||||
* Annotating non-public methods directly is the only way
|
||||
* to get transaction demarcation for the execution of such operations.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
* @see org.springframework.transaction.annotation.Transactional
|
||||
*/
|
||||
public aspect AnnotationTransactionAspect extends AbstractTransactionAspect {
|
||||
|
||||
public AnnotationTransactionAspect() {
|
||||
super(new AnnotationTransactionAttributeSource(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the execution of any public method in a type with the
|
||||
* Transactional annotation, or any subtype of a type with the
|
||||
* Transactional annotation.
|
||||
*/
|
||||
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
|
||||
execution(public * ((@Transactional *)+).*(..)) && @this(Transactional);
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the
|
||||
* Transactional annotation.
|
||||
*/
|
||||
private pointcut executionOfTransactionalMethod() :
|
||||
execution(* *(..)) && @annotation(Transactional);
|
||||
|
||||
/**
|
||||
* Definition of pointcut from super aspect - matched join points
|
||||
* will have Spring transaction management applied.
|
||||
*/
|
||||
protected pointcut transactionalMethodExecution(Object txObject) :
|
||||
(executionOfAnyPublicMethodInAtTransactionalType()
|
||||
|| executionOfTransactionalMethod() )
|
||||
&& this(txObject);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
AspectJ load-time weaving config file to install common Spring aspects.
|
||||
-->
|
||||
<aspectj>
|
||||
|
||||
<!--
|
||||
<weaver options="-showWeaveInfo"/>
|
||||
-->
|
||||
|
||||
<aspects>
|
||||
<aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"/>
|
||||
<aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
|
||||
</aspects>
|
||||
|
||||
</aspectj>
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
AspectJ load-time weaving config file to install common Spring aspects.
|
||||
-->
|
||||
<aspectj>
|
||||
|
||||
<!--
|
||||
<weaver options="-showWeaveInfo"/>
|
||||
-->
|
||||
|
||||
<aspects>
|
||||
<aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"/>
|
||||
<aspect name="org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect"/>
|
||||
<aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
|
||||
</aspects>
|
||||
|
||||
</aspectj>
|
||||
|
||||
+146
-146
@@ -1,146 +1,146 @@
|
||||
/*
|
||||
* Copyright 2009 SpringSource Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test for static entity mocking framework.
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
@MockStaticEntityMethods
|
||||
@RunWith(JUnit4.class)
|
||||
public class AnnotationDrivenStaticEntityMockingControlTest {
|
||||
|
||||
@Test
|
||||
public void testNoArgIntReturn() {
|
||||
int expectedCount = 13;
|
||||
Person.countPeople();
|
||||
expectReturn(expectedCount);
|
||||
playback();
|
||||
Assert.assertEquals(expectedCount, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected=PersistenceException.class)
|
||||
public void testNoArgThrows() {
|
||||
Person.countPeople();
|
||||
expectThrow(new PersistenceException());
|
||||
playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodMatches() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLongSeriesOfCalls() {
|
||||
long id1 = 13;
|
||||
long id2 = 24;
|
||||
Person found1 = new Person();
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person found2 = new Person();
|
||||
Person.findPerson(id2);
|
||||
expectReturn(found2);
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person.countPeople();
|
||||
expectReturn(0);
|
||||
playback();
|
||||
|
||||
Assert.assertEquals(found1, Person.findPerson(id1));
|
||||
Assert.assertEquals(found2, Person.findPerson(id2));
|
||||
Assert.assertEquals(found1, Person.findPerson(id1));
|
||||
Assert.assertEquals(0, Person.countPeople());
|
||||
}
|
||||
|
||||
// Note delegation is used when tests are invalid and should fail, as otherwise
|
||||
// the failure will occur on the verify() method in the aspect after
|
||||
// this method returns, failing the test case
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
try {
|
||||
new Delegate().testArgMethodNoMatchExpectReturn();
|
||||
Assert.fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
new Delegate().testArgMethodNoMatchExpectThrow();
|
||||
}
|
||||
|
||||
private void called(Person found, long id) {
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReentrant() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
called(found, id);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testRejectUnexpectedCall() {
|
||||
new Delegate().rejectUnexpectedCall();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testFailTooFewCalls() {
|
||||
new Delegate().failTooFewCalls();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
// Test that verification check doesn't blow up if no replay() call happened
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverReplay() {
|
||||
new Delegate().doesntEverReplay();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverSetReturn() {
|
||||
new Delegate().doesntEverSetReturn();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test for static entity mocking framework.
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
@MockStaticEntityMethods
|
||||
@RunWith(JUnit4.class)
|
||||
public class AnnotationDrivenStaticEntityMockingControlTest {
|
||||
|
||||
@Test
|
||||
public void testNoArgIntReturn() {
|
||||
int expectedCount = 13;
|
||||
Person.countPeople();
|
||||
expectReturn(expectedCount);
|
||||
playback();
|
||||
Assert.assertEquals(expectedCount, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected=PersistenceException.class)
|
||||
public void testNoArgThrows() {
|
||||
Person.countPeople();
|
||||
expectThrow(new PersistenceException());
|
||||
playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodMatches() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLongSeriesOfCalls() {
|
||||
long id1 = 13;
|
||||
long id2 = 24;
|
||||
Person found1 = new Person();
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person found2 = new Person();
|
||||
Person.findPerson(id2);
|
||||
expectReturn(found2);
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person.countPeople();
|
||||
expectReturn(0);
|
||||
playback();
|
||||
|
||||
Assert.assertEquals(found1, Person.findPerson(id1));
|
||||
Assert.assertEquals(found2, Person.findPerson(id2));
|
||||
Assert.assertEquals(found1, Person.findPerson(id1));
|
||||
Assert.assertEquals(0, Person.countPeople());
|
||||
}
|
||||
|
||||
// Note delegation is used when tests are invalid and should fail, as otherwise
|
||||
// the failure will occur on the verify() method in the aspect after
|
||||
// this method returns, failing the test case
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
try {
|
||||
new Delegate().testArgMethodNoMatchExpectReturn();
|
||||
Assert.fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
new Delegate().testArgMethodNoMatchExpectThrow();
|
||||
}
|
||||
|
||||
private void called(Person found, long id) {
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReentrant() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
called(found, id);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testRejectUnexpectedCall() {
|
||||
new Delegate().rejectUnexpectedCall();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testFailTooFewCalls() {
|
||||
new Delegate().failTooFewCalls();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
// Test that verification check doesn't blow up if no replay() call happened
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverReplay() {
|
||||
new Delegate().doesntEverReplay();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverSetReturn() {
|
||||
new Delegate().doesntEverSetReturn();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+92
-76
@@ -1,76 +1,92 @@
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl;
|
||||
import org.springframework.mock.staticmock.MockStaticEntityMethods;
|
||||
|
||||
//Used because verification failures occur after method returns,
|
||||
//so we can't test for them in the test case itself
|
||||
@MockStaticEntityMethods
|
||||
@Ignore // This isn't meant for direct testing; rather it is driven from AnnotationDrivenStaticEntityMockingControl
|
||||
public class Delegate {
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failTooFewCalls() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverReplay() {
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverSetReturn() {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectUnexpectedCall() {
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected=RemoteException.class)
|
||||
public void testVerificationFailsEvenWhenTestFailsInExpectedManner() throws RemoteException {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
// No calls to allow verification failure
|
||||
throw new RemoteException();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl;
|
||||
import org.springframework.mock.staticmock.MockStaticEntityMethods;
|
||||
|
||||
//Used because verification failures occur after method returns,
|
||||
//so we can't test for them in the test case itself
|
||||
@MockStaticEntityMethods
|
||||
@Ignore // This isn't meant for direct testing; rather it is driven from AnnotationDrivenStaticEntityMockingControl
|
||||
public class Delegate {
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failTooFewCalls() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverReplay() {
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverSetReturn() {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectUnexpectedCall() {
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected=RemoteException.class)
|
||||
public void testVerificationFailsEvenWhenTestFailsInExpectedManner() throws RemoteException {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
// No calls to allow verification failure
|
||||
throw new RemoteException();
|
||||
}
|
||||
}
|
||||
|
||||
+24
-8
@@ -1,8 +1,24 @@
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
@Entity
|
||||
public class Person {
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
@Entity
|
||||
public class Person {
|
||||
}
|
||||
|
||||
|
||||
+100
-84
@@ -1,84 +1,100 @@
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
privileged aspect Person_Roo_Entity {
|
||||
|
||||
@javax.persistence.PersistenceContext
|
||||
transient javax.persistence.EntityManager Person.entityManager;
|
||||
|
||||
@javax.persistence.Id
|
||||
@javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
|
||||
@javax.persistence.Column(name = "id")
|
||||
private java.lang.Long Person.id;
|
||||
|
||||
@javax.persistence.Version
|
||||
@javax.persistence.Column(name = "version")
|
||||
private java.lang.Integer Person.version;
|
||||
|
||||
public java.lang.Long Person.getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void Person.setId(java.lang.Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public java.lang.Integer Person.getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public void Person.setVersion(java.lang.Integer version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.persist() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.persist(this);
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.remove() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.remove(this);
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.flush() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.flush();
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.merge() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
Person merged = this.entityManager.merge(this);
|
||||
this.entityManager.flush();
|
||||
this.id = merged.getId();
|
||||
}
|
||||
|
||||
public static long Person.countPeople() {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return (Long) em.createQuery("select count(o) from Person o").getSingleResult();
|
||||
}
|
||||
|
||||
public static java.util.List<Person> Person.findAllPeople() {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.createQuery("select o from Person o").getResultList();
|
||||
}
|
||||
|
||||
public static Person Person.findPerson(java.lang.Long id) {
|
||||
if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Person");
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.find(Person.class, id);
|
||||
}
|
||||
|
||||
public static java.util.List<Person> Person.findPersonEntries(int firstResult, int maxResults) {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.createQuery("select o from Person o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
privileged aspect Person_Roo_Entity {
|
||||
|
||||
@javax.persistence.PersistenceContext
|
||||
transient javax.persistence.EntityManager Person.entityManager;
|
||||
|
||||
@javax.persistence.Id
|
||||
@javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
|
||||
@javax.persistence.Column(name = "id")
|
||||
private java.lang.Long Person.id;
|
||||
|
||||
@javax.persistence.Version
|
||||
@javax.persistence.Column(name = "version")
|
||||
private java.lang.Integer Person.version;
|
||||
|
||||
public java.lang.Long Person.getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void Person.setId(java.lang.Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public java.lang.Integer Person.getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public void Person.setVersion(java.lang.Integer version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.persist() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.persist(this);
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.remove() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.remove(this);
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.flush() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.flush();
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.merge() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
Person merged = this.entityManager.merge(this);
|
||||
this.entityManager.flush();
|
||||
this.id = merged.getId();
|
||||
}
|
||||
|
||||
public static long Person.countPeople() {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return (Long) em.createQuery("select count(o) from Person o").getSingleResult();
|
||||
}
|
||||
|
||||
public static java.util.List<Person> Person.findAllPeople() {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.createQuery("select o from Person o").getResultList();
|
||||
}
|
||||
|
||||
public static Person Person.findPerson(java.lang.Long id) {
|
||||
if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Person");
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.find(Person.class, id);
|
||||
}
|
||||
|
||||
public static java.util.List<Person> Person.findPersonEntries(int firstResult, int maxResults) {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.createQuery("select o from Person o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author 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.scheduling.aspectj;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import static junit.framework.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.AsyncResult;
|
||||
|
||||
/**
|
||||
* @author Ramnivas Laddad
|
||||
*/
|
||||
public class AnnotationAsyncExecutionAspectTests {
|
||||
|
||||
private static final long WAIT_TIME = 1000; //milli seconds
|
||||
|
||||
private CountingExecutor executor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
executor = new CountingExecutor();
|
||||
AnnotationAsyncExecutionAspect.aspectOf().setExecutor(executor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethodGetsRoutedAsynchronously() {
|
||||
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
|
||||
obj.incrementAsync();
|
||||
executor.waitForCompletion();
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethodReturningFutureGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException {
|
||||
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
|
||||
Future<Integer> future = obj.incrementReturningAFuture();
|
||||
// No need to executor.waitForCompletion() as future.get() will have the same effect
|
||||
assertEquals(5, future.get().intValue());
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syncMethodGetsRoutedSynchronously() {
|
||||
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
|
||||
obj.increment();
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(0, executor.submitStartCounter);
|
||||
assertEquals(0, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void voidMethodInAsyncClassGetsRoutedAsynchronously() {
|
||||
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
|
||||
obj.increment();
|
||||
executor.waitForCompletion();
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodReturningFutureInAsyncClassGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException {
|
||||
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
|
||||
Future<Integer> future = obj.incrementReturningAFuture();
|
||||
assertEquals(5, future.get().intValue());
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodReturningNonVoidNonFutureInAsyncClassGetsRoutedSynchronously() {
|
||||
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
|
||||
int returnValue = obj.return5();
|
||||
assertEquals(5, returnValue);
|
||||
assertEquals(0, executor.submitStartCounter);
|
||||
assertEquals(0, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class CountingExecutor extends SimpleAsyncTaskExecutor {
|
||||
int submitStartCounter;
|
||||
int submitCompleteCounter;
|
||||
|
||||
@Override
|
||||
public <T> Future<T> submit(Callable<T> task) {
|
||||
submitStartCounter++;
|
||||
Future<T> future = super.submit(task);
|
||||
submitCompleteCounter++;
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
public synchronized void waitForCompletion() {
|
||||
try {
|
||||
wait(WAIT_TIME);
|
||||
} catch (InterruptedException e) {
|
||||
Assert.fail("Didn't finish the async job in " + WAIT_TIME + " milliseconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class ClassWithoutAsyncAnnotation {
|
||||
int counter;
|
||||
|
||||
@Async public void incrementAsync() {
|
||||
counter++;
|
||||
}
|
||||
|
||||
public void increment() {
|
||||
counter++;
|
||||
}
|
||||
|
||||
@Async public Future<Integer> incrementReturningAFuture() {
|
||||
counter++;
|
||||
return new AsyncResult<Integer>(5);
|
||||
}
|
||||
|
||||
// It should be an error to attach @Async to a method that returns a non-void
|
||||
// or non-Future.
|
||||
// We need to keep this commented out, otherwise there will be a compile-time error.
|
||||
// Please uncomment and re-comment this periodically to check that the compiler
|
||||
// produces an error message due to the 'declare error' statement
|
||||
// in AnnotationAsyncExecutionAspect
|
||||
// @Async public int getInt() {
|
||||
// return 0;
|
||||
// }
|
||||
}
|
||||
|
||||
@Async
|
||||
static class ClassWithAsyncAnnotation {
|
||||
int counter;
|
||||
|
||||
public void increment() {
|
||||
counter++;
|
||||
}
|
||||
|
||||
// Manually check that there is a warning from the 'declare warning' statement in AnnotationAsynchExecutionAspect
|
||||
public int return5() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
public Future<Integer> incrementReturningAFuture() {
|
||||
counter++;
|
||||
return new AsyncResult<Integer>(5);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@ Import-Template:
|
||||
org.aspectj.*;version=${aj.osgi.range};resolution:=optional,
|
||||
org.springframework.beans.*;version=${spring.osgi.range},
|
||||
org.springframework.transaction.*;version=${spring.osgi.range};resolution:=optional,
|
||||
org.springframework.core.task.*;version=${spring.osgi.range};resolution:=optional,
|
||||
org.springframework.orm.jpa.*;version=${spring.osgi.range};resolution:=optional,
|
||||
org.springframework.dao.*;version=${spring.osgi.range};resolution:=optional
|
||||
Ignored-Existing-Headers:
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
<publications>
|
||||
<artifact name="${ant.project.name}"/>
|
||||
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
|
||||
<artifact name="license" type="license" ext="txt"/>
|
||||
<artifact name="notice" type="notice" ext="txt"/>
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
@@ -28,7 +30,7 @@
|
||||
<dependency org="org.springframework" name="org.springframework.core" rev="latest.integration" conf="compile->compile"/>
|
||||
<!-- test dependencies -->
|
||||
<dependency org="org.apache.log4j" name="com.springsource.org.apache.log4j" rev="1.2.15" conf="test->runtime"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${org.junit.version}" conf="test->runtime"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->runtime"/>
|
||||
<dependency org="org.easymock" name="com.springsource.org.easymock" rev="2.5.1" conf="test->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.asm" rev="latest.integration" conf="compile->compile"/>
|
||||
</dependencies>
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.0.4.BUILD-SNAPSHOT</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.0.4.BUILD-SNAPSHOT</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -92,4 +92,15 @@ public interface BeanWrapper extends ConfigurablePropertyAccessor {
|
||||
*/
|
||||
boolean isAutoGrowNestedPaths();
|
||||
|
||||
/**
|
||||
* Specify a limit for array and collection auto-growing.
|
||||
* <p>Default is unlimited on a plain BeanWrapper.
|
||||
*/
|
||||
void setAutoGrowCollectionLimit(int autoGrowCollectionLimit);
|
||||
|
||||
/**
|
||||
* Return the limit for array and collection auto-growing.
|
||||
*/
|
||||
int getAutoGrowCollectionLimit();
|
||||
|
||||
}
|
||||
|
||||
+57
-43
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -120,6 +120,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
|
||||
private boolean autoGrowNestedPaths = false;
|
||||
|
||||
private int autoGrowCollectionLimit = Integer.MAX_VALUE;
|
||||
|
||||
|
||||
/**
|
||||
* Create new empty BeanWrapperImpl. Wrapped instance needs to be set afterwards.
|
||||
@@ -184,6 +186,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
setWrappedInstance(object, nestedPath, superBw.getWrappedInstance());
|
||||
setExtractOldValueForEditor(superBw.isExtractOldValueForEditor());
|
||||
setAutoGrowNestedPaths(superBw.isAutoGrowNestedPaths());
|
||||
setAutoGrowCollectionLimit(superBw.getAutoGrowCollectionLimit());
|
||||
setConversionService(superBw.getConversionService());
|
||||
setSecurityContext(superBw.acc);
|
||||
}
|
||||
@@ -251,22 +254,38 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
|
||||
/**
|
||||
* If this BeanWrapper should "auto grow" nested paths.
|
||||
* When true, auto growth is triggered on nested paths when null values are encountered.
|
||||
* When true, auto growth is triggered on collection properties when out of bounds indexes are accessed.
|
||||
* Default is false.
|
||||
* Set whether this BeanWrapper should attempt to "auto-grow" a nested path that contains a null value.
|
||||
* <p>If "true", a null path location will be populated with a default object value and traversed
|
||||
* instead of resulting in a {@link NullValueInNestedPathException}. Turning this flag on also
|
||||
* enables auto-growth of collection elements when accessing an out-of-bounds index.
|
||||
* <p>Default is "false" on a plain BeanWrapper.
|
||||
*/
|
||||
public void setAutoGrowNestedPaths(boolean autoGrowNestedPaths) {
|
||||
this.autoGrowNestedPaths = autoGrowNestedPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this BeanWrapper should "auto grow" nested paths.
|
||||
* Return whether "auto-growing" of nested paths has been activated.
|
||||
*/
|
||||
public boolean isAutoGrowNestedPaths() {
|
||||
return this.autoGrowNestedPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a limit for array and collection auto-growing.
|
||||
* <p>Default is unlimited on a plain BeanWrapper.
|
||||
*/
|
||||
public void setAutoGrowCollectionLimit(int autoGrowCollectionLimit) {
|
||||
this.autoGrowCollectionLimit = autoGrowCollectionLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the limit for array and collection auto-growing.
|
||||
*/
|
||||
public int getAutoGrowCollectionLimit() {
|
||||
return this.autoGrowCollectionLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the security context used during the invocation of the wrapped instance methods.
|
||||
* Can be null.
|
||||
@@ -586,21 +605,25 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
PropertyTokenHolder tokens = new PropertyTokenHolder();
|
||||
tokens.actualName = propertyName;
|
||||
tokens.canonicalName = propertyName;
|
||||
setPropertyValue(tokens, createDefaultPropertyValue(tokens));
|
||||
return getPropertyValue(tokens);
|
||||
return setDefaultValue(tokens);
|
||||
}
|
||||
|
||||
private Object setDefaultValue(PropertyTokenHolder tokens) {
|
||||
setPropertyValue(tokens, createDefaultPropertyValue(tokens));
|
||||
PropertyValue pv = createDefaultPropertyValue(tokens);
|
||||
setPropertyValue(tokens, pv);
|
||||
return getPropertyValue(tokens);
|
||||
}
|
||||
|
||||
|
||||
private PropertyValue createDefaultPropertyValue(PropertyTokenHolder tokens) {
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(tokens.actualName);
|
||||
Object defaultValue = newValue(pd.getPropertyType(), tokens.canonicalName);
|
||||
Class type = getPropertyType(tokens.canonicalName);
|
||||
if (type == null) {
|
||||
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Could not determine property type for auto-growing a default value");
|
||||
}
|
||||
Object defaultValue = newValue(type, tokens.canonicalName);
|
||||
return new PropertyValue(tokens.canonicalName, defaultValue);
|
||||
}
|
||||
|
||||
|
||||
private Object newValue(Class<?> type, String name) {
|
||||
try {
|
||||
if (type.isArray()) {
|
||||
@@ -630,7 +653,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
"Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new nested BeanWrapper instance.
|
||||
* <p>Default implementation creates a BeanWrapperImpl instance.
|
||||
@@ -791,9 +814,6 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
// must not kick in for map keys but rather only for map values.
|
||||
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType,
|
||||
new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), mapKeyType));
|
||||
// Pass full property name and old value in here, since we want full
|
||||
// conversion ability for map values.
|
||||
growMapIfNecessary(map, convertedMapKey, indexedPropertyName, pd, i + 1);
|
||||
value = map.get(convertedMapKey);
|
||||
}
|
||||
else {
|
||||
@@ -833,15 +853,16 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
return array;
|
||||
}
|
||||
int length = Array.getLength(array);
|
||||
if (index >= length) {
|
||||
if (index >= length && index < this.autoGrowCollectionLimit) {
|
||||
Class<?> componentType = array.getClass().getComponentType();
|
||||
Object newArray = Array.newInstance(componentType, index + 1);
|
||||
System.arraycopy(array, 0, newArray, 0, length);
|
||||
for (int i = length; i < Array.getLength(newArray); i++) {
|
||||
Array.set(newArray, i, newValue(componentType, name));
|
||||
}
|
||||
// TODO this is not efficient because conversion may create a copy ... set directly because we know it is assignable.
|
||||
setPropertyValue(name, newArray);
|
||||
return newArray;
|
||||
return getPropertyValue(name);
|
||||
}
|
||||
else {
|
||||
return array;
|
||||
@@ -855,7 +876,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
if (!this.autoGrowNestedPaths) {
|
||||
return;
|
||||
}
|
||||
if (index >= collection.size()) {
|
||||
int size = collection.size();
|
||||
if (index >= size && index < this.autoGrowCollectionLimit) {
|
||||
Class elementType = GenericCollectionTypeResolver.getCollectionReturnType(pd.getReadMethod(), nestingLevel);
|
||||
if (elementType != null) {
|
||||
for (int i = collection.size(); i < index + 1; i++) {
|
||||
@@ -865,21 +887,6 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void growMapIfNecessary(
|
||||
Map map, Object key, String name, PropertyDescriptor pd, int nestingLevel) {
|
||||
|
||||
if (!this.autoGrowNestedPaths) {
|
||||
return;
|
||||
}
|
||||
if (!map.containsKey(key)) {
|
||||
Class valueType = GenericCollectionTypeResolver.getMapValueReturnType(pd.getReadMethod(), nestingLevel);
|
||||
if (valueType != null) {
|
||||
map.put(key, newValue(valueType, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPropertyValue(String propertyName, Object value) throws BeansException {
|
||||
BeanWrapperImpl nestedBw;
|
||||
@@ -946,13 +953,13 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
"Cannot access indexed value in property referenced " +
|
||||
"in indexed property path '" + propertyName + "': returned null");
|
||||
}
|
||||
else if (propValue.getClass().isArray()) {
|
||||
if (propValue.getClass().isArray()) {
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
|
||||
Class requiredType = propValue.getClass().getComponentType();
|
||||
int arrayIndex = Integer.parseInt(key);
|
||||
Object oldValue = null;
|
||||
try {
|
||||
if (isExtractOldValueForEditor()) {
|
||||
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
|
||||
oldValue = Array.get(propValue, arrayIndex);
|
||||
}
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType,
|
||||
@@ -976,23 +983,30 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType,
|
||||
new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), requiredType));
|
||||
if (index < list.size()) {
|
||||
list.set(index, convertedValue);
|
||||
}
|
||||
else if (index >= list.size()) {
|
||||
for (int i = list.size(); i < index; i++) {
|
||||
int size = list.size();
|
||||
if (index >= size && index < this.autoGrowCollectionLimit) {
|
||||
for (int i = size; i < index; i++) {
|
||||
try {
|
||||
list.add(null);
|
||||
}
|
||||
catch (NullPointerException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Cannot set element with index " + index + " in List of size " +
|
||||
list.size() + ", accessed using property path '" + propertyName +
|
||||
size + ", accessed using property path '" + propertyName +
|
||||
"': List does not support filling up gaps with null elements");
|
||||
}
|
||||
}
|
||||
list.add(convertedValue);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
list.set(index, convertedValue);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Invalid list index in property path '" + propertyName + "'", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (propValue instanceof Map) {
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ public class MutablePropertyValues implements PropertyValues, Serializable {
|
||||
* @see #add(String, Object)
|
||||
*/
|
||||
public MutablePropertyValues() {
|
||||
this.propertyValueList = new ArrayList<PropertyValue>();
|
||||
this.propertyValueList = new ArrayList<PropertyValue>(0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+43
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,7 @@ import java.beans.PropertyEditor;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
@@ -136,7 +137,10 @@ class TypeConverterDelegate {
|
||||
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
|
||||
if (editor == null && conversionService != null && convertedValue != null) {
|
||||
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(convertedValue);
|
||||
TypeDescriptor targetTypeDesc = typeDescriptor.forElementType(requiredType);
|
||||
TypeDescriptor targetTypeDesc = typeDescriptor;
|
||||
if (requiredType != null && !requiredType.isAssignableFrom(typeDescriptor.getType())) {
|
||||
targetTypeDesc = typeDescriptor.forElementType(requiredType);
|
||||
}
|
||||
if (conversionService.canConvert(sourceTypeDesc, targetTypeDesc)) {
|
||||
return (T) conversionService.convert(convertedValue, sourceTypeDesc, targetTypeDesc);
|
||||
}
|
||||
@@ -223,7 +227,8 @@ class TypeConverterDelegate {
|
||||
}
|
||||
if (editor != null) {
|
||||
msg.append(": PropertyEditor [").append(editor.getClass().getName()).append(
|
||||
"] returned inappropriate value");
|
||||
"] returned inappropriate value of type [").append(
|
||||
ClassUtils.getDescriptiveType(convertedValue)).append("]");
|
||||
throw new IllegalArgumentException(msg.toString());
|
||||
}
|
||||
else {
|
||||
@@ -459,11 +464,20 @@ class TypeConverterDelegate {
|
||||
protected Collection convertToTypedCollection(
|
||||
Collection original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
|
||||
|
||||
boolean originalAllowed = requiredType.isInstance(original);
|
||||
if (!originalAllowed && !Collection.class.isAssignableFrom(requiredType)) {
|
||||
if (!Collection.class.isAssignableFrom(requiredType)) {
|
||||
return original;
|
||||
}
|
||||
|
||||
boolean approximable = CollectionFactory.isApproximableCollectionType(requiredType);
|
||||
if (!approximable && !canCreateCopy(requiredType)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Custom Collection type [" + original.getClass().getName() +
|
||||
"] does not allow for creating a copy - injecting original Collection as-is");
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
boolean originalAllowed = requiredType.isInstance(original);
|
||||
MethodParameter methodParam = typeDescriptor.getMethodParameter();
|
||||
Class elementType = null;
|
||||
if (methodParam != null) {
|
||||
@@ -488,14 +502,14 @@ class TypeConverterDelegate {
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cannot access Collection of type [" + original.getClass().getName() +
|
||||
"] - injecting original Collection as-is", ex);
|
||||
"] - injecting original Collection as-is: " + ex);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
Collection convertedCopy;
|
||||
try {
|
||||
if (CollectionFactory.isApproximableCollectionType(requiredType)) {
|
||||
if (approximable) {
|
||||
convertedCopy = CollectionFactory.createApproximateCollection(original, original.size());
|
||||
}
|
||||
else {
|
||||
@@ -505,7 +519,7 @@ class TypeConverterDelegate {
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cannot create copy of Collection type [" + original.getClass().getName() +
|
||||
"] - injecting original Collection as-is", ex);
|
||||
"] - injecting original Collection as-is: " + ex);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
@@ -528,7 +542,7 @@ class TypeConverterDelegate {
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Collection type [" + original.getClass().getName() +
|
||||
"] seems to be read-only - injecting original Collection as-is", ex);
|
||||
"] seems to be read-only - injecting original Collection as-is: " + ex);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
@@ -541,11 +555,20 @@ class TypeConverterDelegate {
|
||||
protected Map convertToTypedMap(
|
||||
Map original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
|
||||
|
||||
boolean originalAllowed = requiredType.isInstance(original);
|
||||
if (!originalAllowed && !Map.class.isAssignableFrom(requiredType)) {
|
||||
if (!Map.class.isAssignableFrom(requiredType)) {
|
||||
return original;
|
||||
}
|
||||
|
||||
boolean approximable = CollectionFactory.isApproximableMapType(requiredType);
|
||||
if (!approximable && !canCreateCopy(requiredType)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Custom Map type [" + original.getClass().getName() +
|
||||
"] does not allow for creating a copy - injecting original Map as-is");
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
boolean originalAllowed = requiredType.isInstance(original);
|
||||
Class keyType = null;
|
||||
Class valueType = null;
|
||||
MethodParameter methodParam = typeDescriptor.getMethodParameter();
|
||||
@@ -572,14 +595,14 @@ class TypeConverterDelegate {
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cannot access Map of type [" + original.getClass().getName() +
|
||||
"] - injecting original Map as-is", ex);
|
||||
"] - injecting original Map as-is: " + ex);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
Map convertedCopy;
|
||||
try {
|
||||
if (CollectionFactory.isApproximableMapType(requiredType)) {
|
||||
if (approximable) {
|
||||
convertedCopy = CollectionFactory.createApproximateMap(original, original.size());
|
||||
}
|
||||
else {
|
||||
@@ -589,7 +612,7 @@ class TypeConverterDelegate {
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cannot create copy of Map type [" + original.getClass().getName() +
|
||||
"] - injecting original Map as-is", ex);
|
||||
"] - injecting original Map as-is: " + ex);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
@@ -617,7 +640,7 @@ class TypeConverterDelegate {
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Map type [" + original.getClass().getName() +
|
||||
"] seems to be read-only - injecting original Map as-is", ex);
|
||||
"] seems to be read-only - injecting original Map as-is: " + ex);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
@@ -638,4 +661,9 @@ class TypeConverterDelegate {
|
||||
null);
|
||||
}
|
||||
|
||||
private boolean canCreateCopy(Class requiredType) {
|
||||
return (!requiredType.isInterface() && !Modifier.isAbstract(requiredType.getModifiers()) &&
|
||||
Modifier.isPublic(requiredType.getModifiers()) && ClassUtils.hasConstructor(requiredType));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+31
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -208,6 +208,11 @@ public abstract class BeanFactoryUtils {
|
||||
* <p>Does consider objects created by FactoryBeans, which means that FactoryBeans
|
||||
* will get initialized. If the object created by the FactoryBean doesn't match,
|
||||
* the raw FactoryBean itself will be matched against the type.
|
||||
* <p><b>Note: Beans of the same name will take precedence at the 'lowest' factory level,
|
||||
* i.e. such beans will be returned from the lowest factory that they are being found in,
|
||||
* hiding corresponding beans in ancestor factories.</b> This feature allows for
|
||||
* 'replacing' beans by explicitly choosing the same bean name in a child factory;
|
||||
* the bean in the ancestor factory won't be visible then, not even for by-type lookups.
|
||||
* @param lbf the bean factory
|
||||
* @param type type of bean to match
|
||||
* @return the Map of matching bean instances, or an empty Map if none
|
||||
@@ -239,12 +244,16 @@ public abstract class BeanFactoryUtils {
|
||||
* Return all beans of the given type or subtypes, also picking up beans defined in
|
||||
* ancestor bean factories if the current bean factory is a HierarchicalBeanFactory.
|
||||
* The returned Map will only contain beans of this type.
|
||||
* <p>Does consider objects created by FactoryBeans if the "allowEagerInit"
|
||||
* flag is set, which means that FactoryBeans will get initialized. If the
|
||||
* object created by the FactoryBean doesn't match, the raw FactoryBean itself
|
||||
* will be matched against the type. If "allowEagerInit" is not set,
|
||||
* only raw FactoryBeans will be checked (which doesn't require initialization
|
||||
* of each FactoryBean).
|
||||
* <p>Does consider objects created by FactoryBeans if the "allowEagerInit" flag is set,
|
||||
* which means that FactoryBeans will get initialized. If the object created by the
|
||||
* FactoryBean doesn't match, the raw FactoryBean itself will be matched against the
|
||||
* type. If "allowEagerInit" is not set, only raw FactoryBeans will be checked
|
||||
* (which doesn't require initialization of each FactoryBean).
|
||||
* <p><b>Note: Beans of the same name will take precedence at the 'lowest' factory level,
|
||||
* i.e. such beans will be returned from the lowest factory that they are being found in,
|
||||
* hiding corresponding beans in ancestor factories.</b> This feature allows for
|
||||
* 'replacing' beans by explicitly choosing the same bean name in a child factory;
|
||||
* the bean in the ancestor factory won't be visible then, not even for by-type lookups.
|
||||
* @param lbf the bean factory
|
||||
* @param type type of bean to match
|
||||
* @param includeNonSingletons whether to include prototype or scoped beans too
|
||||
@@ -291,6 +300,11 @@ public abstract class BeanFactoryUtils {
|
||||
* the raw FactoryBean itself will be matched against the type.
|
||||
* <p>This version of <code>beanOfTypeIncludingAncestors</code> automatically includes
|
||||
* prototypes and FactoryBeans.
|
||||
* <p><b>Note: Beans of the same name will take precedence at the 'lowest' factory level,
|
||||
* i.e. such beans will be returned from the lowest factory that they are being found in,
|
||||
* hiding corresponding beans in ancestor factories.</b> This feature allows for
|
||||
* 'replacing' beans by explicitly choosing the same bean name in a child factory;
|
||||
* the bean in the ancestor factory won't be visible then, not even for by-type lookups.
|
||||
* @param lbf the bean factory
|
||||
* @param type type of bean to match
|
||||
* @return the matching bean instance
|
||||
@@ -315,12 +329,16 @@ public abstract class BeanFactoryUtils {
|
||||
* defined in ancestor bean factories if the current bean factory is a
|
||||
* HierarchicalBeanFactory. Useful convenience method when we expect a
|
||||
* single bean and don't care about the bean name.
|
||||
* <p>Does consider objects created by FactoryBeans if the "allowEagerInit"
|
||||
* flag is set, which means that FactoryBeans will get initialized. If the
|
||||
* object created by the FactoryBean doesn't match, the raw FactoryBean itself
|
||||
* will be matched against the type. If "allowEagerInit" is not set,
|
||||
* only raw FactoryBeans will be checked (which doesn't require initialization
|
||||
* of each FactoryBean).
|
||||
* <p>Does consider objects created by FactoryBeans if the "allowEagerInit" flag is set,
|
||||
* which means that FactoryBeans will get initialized. If the object created by the
|
||||
* FactoryBean doesn't match, the raw FactoryBean itself will be matched against the
|
||||
* type. If "allowEagerInit" is not set, only raw FactoryBeans will be checked
|
||||
* (which doesn't require initialization of each FactoryBean).
|
||||
* <p><b>Note: Beans of the same name will take precedence at the 'lowest' factory level,
|
||||
* i.e. such beans will be returned from the lowest factory that they are being found in,
|
||||
* hiding corresponding beans in ancestor factories.</b> This feature allows for
|
||||
* 'replacing' beans by explicitly choosing the same bean name in a child factory;
|
||||
* the bean in the ancestor factory won't be visible then, not even for by-type lookups.
|
||||
* @param lbf the bean factory
|
||||
* @param type type of bean to match
|
||||
* @param includeNonSingletons whether to include prototype or scoped beans too
|
||||
|
||||
+13
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.beans.factory.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -46,16 +47,25 @@ import java.lang.annotation.Target;
|
||||
* declared value type. In case of a Map, the keys must be declared as
|
||||
* type String and will be resolved to the corresponding bean names.
|
||||
*
|
||||
* <p>Please do consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
|
||||
* <p>Note that actual injection is performed through a
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* BeanPostProcessor} which in turn means that you <em>cannot</em>
|
||||
* use {@code @Autowired} to inject references into
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* BeanPostProcessor} or {@link BeanFactoryPostProcessor} types. Please
|
||||
* consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
|
||||
* class (which, by default, checks for the presence of this annotation).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @since 2.5
|
||||
* @see AutowiredAnnotationBeanPostProcessor
|
||||
* @see Qualifier
|
||||
* @see Value
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Autowired {
|
||||
|
||||
/**
|
||||
|
||||
+50
-65
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,7 +38,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
@@ -51,6 +50,7 @@ import org.springframework.beans.factory.config.InstantiationAwareBeanPostProces
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.Ordered;
|
||||
@@ -62,8 +62,11 @@ import org.springframework.util.ReflectionUtils;
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
|
||||
* that autowires annotated fields, setter methods and arbitrary config methods.
|
||||
* Such members to be injected are detected through a Java 5 annotation:
|
||||
* by default, Spring's {@link Autowired} annotation.
|
||||
* Such members to be injected are detected through a Java 5 annotation: by default,
|
||||
* Spring's {@link Autowired @Autowired} and {@link Value @Value} annotations.
|
||||
*
|
||||
* <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
|
||||
* if available, as a direct alternative to Spring's own <code>@Autowired</code>.
|
||||
*
|
||||
* <p>Only one constructor (at max) of any given bean class may carry this
|
||||
* annotation with the 'required' parameter set to <code>true</code>,
|
||||
@@ -78,27 +81,25 @@ import org.springframework.util.ReflectionUtils;
|
||||
* <p>Fields are injected right after construction of a bean, before any
|
||||
* config methods are invoked. Such a config field does not have to be public.
|
||||
*
|
||||
* <p>Config methods may have an arbitrary name and any number of arguments;
|
||||
* each of those arguments will be autowired with a matching bean in the
|
||||
* Spring container. Bean property setter methods are effectively just
|
||||
* a special case of such a general config method. Such config methods
|
||||
* do not have to be public.
|
||||
*
|
||||
* <p>Also supports JSR-330's {@link javax.inject.Inject} annotation, if available.
|
||||
* <p>Config methods may have an arbitrary name and any number of arguments; each of
|
||||
* those arguments will be autowired with a matching bean in the Spring container.
|
||||
* Bean property setter methods are effectively just a special case of such a
|
||||
* general config method. Config methods do not have to be public.
|
||||
*
|
||||
* <p>Note: A default AutowiredAnnotationBeanPostProcessor will be registered
|
||||
* by the "context:annotation-config" and "context:component-scan" XML tags.
|
||||
* Remove or turn off the default annotation configuration there if you intend
|
||||
* to specify a custom AutowiredAnnotationBeanPostProcessor bean definition.
|
||||
* <p><b>NOTE:</b> Annotation injection will be performed <i>before</i> XML injection; thus
|
||||
* the latter configuration will override the former for properties wired through
|
||||
* both approaches.
|
||||
*
|
||||
* <p><b>NOTE:</b> Annotation injection will be performed <i>before</i> XML injection;
|
||||
* thus the latter configuration will override the former for properties wired through
|
||||
* both approaches.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @since 2.5
|
||||
* @see #setAutowiredAnnotationType
|
||||
* @see Autowired
|
||||
* @see Value
|
||||
*/
|
||||
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
|
||||
implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
|
||||
@@ -116,8 +117,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
private final Map<Class<?>, Constructor[]> candidateConstructorsCache =
|
||||
new ConcurrentHashMap<Class<?>, Constructor[]>();
|
||||
private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache =
|
||||
new ConcurrentHashMap<Class<?>, Constructor<?>[]>();
|
||||
|
||||
private final Map<Class<?>, InjectionMetadata> injectionMetadataCache =
|
||||
new ConcurrentHashMap<Class<?>, InjectionMetadata>();
|
||||
@@ -306,7 +307,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
|
||||
|
||||
private InjectionMetadata findAutowiringMetadata(Class clazz) {
|
||||
private InjectionMetadata findAutowiringMetadata(Class<?> clazz) {
|
||||
// Quick check on the concurrent map first, with minimal locking.
|
||||
InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);
|
||||
if (metadata == null) {
|
||||
@@ -321,7 +322,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private InjectionMetadata buildAutowiringMetadata(Class clazz) {
|
||||
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
|
||||
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
Class<?> targetClass = clazz;
|
||||
|
||||
@@ -341,7 +342,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
}
|
||||
for (Method method : targetClass.getDeclaredMethods()) {
|
||||
Annotation annotation = findAutowiredAnnotation(method);
|
||||
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
Annotation annotation = BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod) ?
|
||||
findAutowiredAnnotation(bridgedMethod) : findAutowiredAnnotation(method);
|
||||
if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
@@ -469,14 +472,14 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
|
||||
}
|
||||
else {
|
||||
DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
value = beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);
|
||||
this.cachedFieldValue = descriptor;
|
||||
value = beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
|
||||
if (value != null) {
|
||||
if (value != null || this.required) {
|
||||
this.cachedFieldValue = descriptor;
|
||||
registerDependentBeans(beanName, autowiredBeanNames);
|
||||
if (autowiredBeanNames.size() == 1) {
|
||||
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
||||
@@ -492,10 +495,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
this.cached = true;
|
||||
}
|
||||
else {
|
||||
// Already cached in the meantime...
|
||||
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (value != null) {
|
||||
@@ -528,11 +527,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
|
||||
@Override
|
||||
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
|
||||
if (this.skip == null && this.pd != null && pvs != null && pvs.contains(this.pd.getName())) {
|
||||
// Explicit value provided as part of the bean definition.
|
||||
this.skip = Boolean.TRUE;
|
||||
}
|
||||
if (this.skip != null && this.skip) {
|
||||
if (checkPropertySkipping(pvs)) {
|
||||
return;
|
||||
}
|
||||
Method method = (Method) this.member;
|
||||
@@ -543,26 +538,29 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
arguments = resolveCachedArguments(beanName);
|
||||
}
|
||||
else {
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
arguments = new Object[paramTypes.length];
|
||||
DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<String>(paramTypes.length);
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(method, i);
|
||||
GenericTypeResolver.resolveParameterType(methodParam, bean.getClass());
|
||||
descriptors[i] = new DependencyDescriptor(methodParam, this.required);
|
||||
arguments[i] = beanFactory.resolveDependency(
|
||||
descriptors[i], beanName, autowiredBeanNames, typeConverter);
|
||||
if (arguments[i] == null && !this.required) {
|
||||
arguments = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
arguments = new Object[paramTypes.length];
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<String>(arguments.length);
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
this.cachedMethodArguments = new Object[arguments.length];
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(method, i);
|
||||
GenericTypeResolver.resolveParameterType(methodParam, bean.getClass());
|
||||
DependencyDescriptor descriptor = new DependencyDescriptor(methodParam, this.required);
|
||||
this.cachedMethodArguments[i] = descriptor;
|
||||
arguments[i] = beanFactory.resolveDependency(
|
||||
descriptor, beanName, autowiredBeanNames, typeConverter);
|
||||
if (arguments[i] == null) {
|
||||
arguments = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (arguments != null) {
|
||||
this.cachedMethodArguments = new Object[arguments.length];
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
this.cachedMethodArguments[i] = descriptors[i];
|
||||
}
|
||||
registerDependentBeans(beanName, autowiredBeanNames);
|
||||
if (autowiredBeanNames.size() == paramTypes.length) {
|
||||
Iterator<String> it = autowiredBeanNames.iterator();
|
||||
@@ -573,9 +571,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
this.cachedMethodArguments[i] = new RuntimeBeanReference(autowiredBeanName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.cachedMethodArguments[i] = arguments[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -584,18 +579,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
this.cached = true;
|
||||
}
|
||||
else {
|
||||
// Already cached in the meantime...
|
||||
arguments = resolveCachedArguments(beanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.skip == null) {
|
||||
if (this.pd != null && pvs instanceof MutablePropertyValues) {
|
||||
((MutablePropertyValues) pvs).registerProcessedProperty(this.pd.getName());
|
||||
}
|
||||
this.skip = Boolean.FALSE;
|
||||
}
|
||||
if (arguments != null) {
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
method.invoke(bean, arguments);
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2011 the original author 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,10 +34,10 @@ import java.lang.annotation.Target;
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface Configurable {
|
||||
|
||||
/**
|
||||
|
||||
+20
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -147,10 +147,7 @@ public class InjectionMetadata {
|
||||
field.set(target, getResourceToInject(target, requestingBeanName));
|
||||
}
|
||||
else {
|
||||
if (this.skip == null) {
|
||||
this.skip = checkPropertySkipping(pvs);
|
||||
}
|
||||
if (this.skip) {
|
||||
if (checkPropertySkipping(pvs)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -170,16 +167,26 @@ public class InjectionMetadata {
|
||||
* affected property as processed for other processors to ignore it.
|
||||
*/
|
||||
protected boolean checkPropertySkipping(PropertyValues pvs) {
|
||||
if (this.pd != null && pvs != null) {
|
||||
if (pvs.contains(this.pd.getName())) {
|
||||
// Explicit value provided as part of the bean definition.
|
||||
return true;
|
||||
}
|
||||
else if (pvs instanceof MutablePropertyValues) {
|
||||
((MutablePropertyValues) pvs).registerProcessedProperty(this.pd.getName());
|
||||
if (this.skip == null) {
|
||||
if (pvs != null) {
|
||||
synchronized (pvs) {
|
||||
if (this.skip == null) {
|
||||
if (this.pd != null) {
|
||||
if (pvs.contains(this.pd.getName())) {
|
||||
// Explicit value provided as part of the bean definition.
|
||||
this.skip = true;
|
||||
return true;
|
||||
}
|
||||
else if (pvs instanceof MutablePropertyValues) {
|
||||
((MutablePropertyValues) pvs).registerProcessedProperty(this.pd.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.skip = false;
|
||||
}
|
||||
return false;
|
||||
return this.skip;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,9 +31,10 @@ import java.lang.annotation.Target;
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see Autowired
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface Qualifier {
|
||||
|
||||
+6
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -164,8 +164,11 @@ public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanP
|
||||
* @return <code>true</code> to skip the bean; <code>false</code> to process it
|
||||
*/
|
||||
protected boolean shouldSkip(ConfigurableListableBeanFactory beanFactory, String beanName) {
|
||||
return (beanFactory != null && beanFactory.containsBeanDefinition(beanName) &&
|
||||
Boolean.TRUE.equals(beanFactory.getBeanDefinition(beanName).getAttribute(SKIP_REQUIRED_CHECK_ATTRIBUTE)));
|
||||
if (beanFactory == null || !beanFactory.containsBeanDefinition(beanName)) {
|
||||
return false;
|
||||
}
|
||||
Object value = beanFactory.getBeanDefinition(beanName).getAttribute(SKIP_REQUIRED_CHECK_ATTRIBUTE);
|
||||
return (value != null && (Boolean.TRUE.equals(value) || Boolean.valueOf(value.toString())));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+15
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.beans.factory.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -31,13 +32,25 @@ import java.lang.annotation.Target;
|
||||
* <p>A common use case is to assign default field values using
|
||||
* "#{systemProperties.myProp}" style expressions.
|
||||
*
|
||||
* <p>Note that actual processing of the {@code @Value} annotation is performed
|
||||
* by a {@link org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* BeanPostProcessor} which in turn means that you <em>cannot</em> use
|
||||
* {@code @Value} within
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* BeanPostProcessor} or {@link BeanFactoryPostProcessor} types. Please
|
||||
* consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
|
||||
* class (which, by default, checks for the presence of this annotation).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @see AutowiredAnnotationBeanPostProcessor
|
||||
* @see Autowired
|
||||
* @see org.springframework.beans.factory.config.BeanExpressionResolver
|
||||
* @see org.springframework.beans.factory.support.AutowireCandidateResolver#getSuggestedValue
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Value {
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -115,7 +115,7 @@ public class BeanDefinitionVisitor {
|
||||
}
|
||||
|
||||
protected void visitFactoryMethodName(BeanDefinition beanDefinition) {
|
||||
String factoryMethodName = beanDefinition.getFactoryBeanName();
|
||||
String factoryMethodName = beanDefinition.getFactoryMethodName();
|
||||
if (factoryMethodName != null) {
|
||||
String resolvedName = resolveStringValue(factoryMethodName);
|
||||
if (!factoryMethodName.equals(resolvedName)) {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -173,7 +173,7 @@ public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, Single
|
||||
* @param requiredType type of the property
|
||||
* @param propertyEditorClass the {@link PropertyEditor} class to register
|
||||
*/
|
||||
void registerCustomEditor(Class requiredType, Class<? extends PropertyEditor> propertyEditorClass);
|
||||
void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass);
|
||||
|
||||
/**
|
||||
* Initialize the given PropertyEditorRegistry with the custom editors
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,7 +42,7 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
public class ConstructorArgumentValues {
|
||||
|
||||
private final Map<Integer, ValueHolder> indexedArgumentValues = new LinkedHashMap<Integer, ValueHolder>();
|
||||
private final Map<Integer, ValueHolder> indexedArgumentValues = new LinkedHashMap<Integer, ValueHolder>(0);
|
||||
|
||||
private final List<ValueHolder> genericArgumentValues = new LinkedList<ValueHolder>();
|
||||
|
||||
|
||||
+17
-15
@@ -28,7 +28,6 @@ import java.security.PrivilegedExceptionAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -144,7 +143,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
|
||||
/** Cache of filtered PropertyDescriptors: bean Class -> PropertyDescriptor array */
|
||||
private final Map<Class, PropertyDescriptor[]> filteredPropertyDescriptorsCache =
|
||||
new HashMap<Class, PropertyDescriptor[]>();
|
||||
new ConcurrentHashMap<Class, PropertyDescriptor[]>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -567,7 +566,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class predictBeanType(String beanName, RootBeanDefinition mbd, Class[] typesToMatch) {
|
||||
protected Class predictBeanType(String beanName, RootBeanDefinition mbd, Class... typesToMatch) {
|
||||
Class beanClass;
|
||||
if (mbd.getFactoryMethodName() != null) {
|
||||
beanClass = getTypeForFactoryMethod(beanName, mbd, typesToMatch);
|
||||
@@ -1201,22 +1200,25 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* @see #isExcludedFromDependencyCheck
|
||||
*/
|
||||
protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw) {
|
||||
synchronized (this.filteredPropertyDescriptorsCache) {
|
||||
PropertyDescriptor[] filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
|
||||
if (filtered == null) {
|
||||
List<PropertyDescriptor> pds =
|
||||
new LinkedList<PropertyDescriptor>(Arrays.asList(bw.getPropertyDescriptors()));
|
||||
for (Iterator<PropertyDescriptor> it = pds.iterator(); it.hasNext();) {
|
||||
PropertyDescriptor pd = it.next();
|
||||
if (isExcludedFromDependencyCheck(pd)) {
|
||||
it.remove();
|
||||
PropertyDescriptor[] filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
|
||||
if (filtered == null) {
|
||||
synchronized (this.filteredPropertyDescriptorsCache) {
|
||||
filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
|
||||
if (filtered == null) {
|
||||
List<PropertyDescriptor> pds =
|
||||
new LinkedList<PropertyDescriptor>(Arrays.asList(bw.getPropertyDescriptors()));
|
||||
for (Iterator<PropertyDescriptor> it = pds.iterator(); it.hasNext();) {
|
||||
PropertyDescriptor pd = it.next();
|
||||
if (isExcludedFromDependencyCheck(pd)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
filtered = pds.toArray(new PropertyDescriptor[pds.size()]);
|
||||
this.filteredPropertyDescriptorsCache.put(bw.getWrappedClass(), filtered);
|
||||
}
|
||||
filtered = pds.toArray(new PropertyDescriptor[pds.size()]);
|
||||
this.filteredPropertyDescriptorsCache.put(bw.getWrappedClass(), filtered);
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
private boolean primary = false;
|
||||
|
||||
private final Map<String, AutowireCandidateQualifier> qualifiers =
|
||||
new LinkedHashMap<String, AutowireCandidateQualifier>();
|
||||
new LinkedHashMap<String, AutowireCandidateQualifier>(0);
|
||||
|
||||
private boolean nonPublicAccessAllowed = true;
|
||||
|
||||
|
||||
+33
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,6 +42,7 @@ import org.springframework.beans.PropertyEditorRegistry;
|
||||
import org.springframework.beans.PropertyEditorRegistrySupport;
|
||||
import org.springframework.beans.SimpleTypeConverter;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.beans.TypeMismatchException;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.BeanCurrentlyInCreationException;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
@@ -166,6 +167,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
|
||||
new NamedThreadLocal<Object>("Prototype beans currently in creation");
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AbstractBeanFactory.
|
||||
*/
|
||||
@@ -189,7 +191,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
public Object getBean(String name) throws BeansException {
|
||||
return doGetBean(name, null, null, false);
|
||||
}
|
||||
|
||||
|
||||
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
|
||||
return doGetBean(name, requiredType, null, false);
|
||||
}
|
||||
@@ -346,7 +348,16 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
|
||||
// Check if required type matches the type of the actual bean instance.
|
||||
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
|
||||
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
|
||||
try {
|
||||
return getTypeConverter().convertIfNecessary(bean, requiredType);
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to convert bean '" + name + "' to required type [" +
|
||||
ClassUtils.getQualifiedName(requiredType) + "]", ex);
|
||||
}
|
||||
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
|
||||
}
|
||||
}
|
||||
return (T) bean;
|
||||
}
|
||||
@@ -373,6 +384,9 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
return !BeanFactoryUtils.isFactoryDereference(name);
|
||||
}
|
||||
}
|
||||
else if (containsSingleton(beanName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
else {
|
||||
// No singleton instance found -> check bean definition.
|
||||
@@ -465,6 +479,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
typeToMatch.isAssignableFrom(beanInstance.getClass());
|
||||
}
|
||||
}
|
||||
else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
|
||||
// null instance registered
|
||||
return false;
|
||||
}
|
||||
|
||||
else {
|
||||
// No singleton instance found -> check bean definition.
|
||||
@@ -524,6 +542,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
return beanInstance.getClass();
|
||||
}
|
||||
}
|
||||
else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
|
||||
// null instance registered
|
||||
return null;
|
||||
}
|
||||
|
||||
else {
|
||||
// No singleton instance found -> check bean definition.
|
||||
@@ -671,7 +693,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
return this.propertyEditorRegistrars;
|
||||
}
|
||||
|
||||
public void registerCustomEditor(Class requiredType, Class<? extends PropertyEditor> propertyEditorClass) {
|
||||
public void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass) {
|
||||
Assert.notNull(requiredType, "Required type must not be null");
|
||||
Assert.isAssignable(PropertyEditor.class, propertyEditorClass);
|
||||
this.customEditors.put(requiredType, propertyEditorClass);
|
||||
@@ -860,6 +882,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
if (beanInstance != null) {
|
||||
return (beanInstance instanceof FactoryBean);
|
||||
}
|
||||
else if (containsSingleton(beanName)) {
|
||||
// null instance registered
|
||||
return false;
|
||||
}
|
||||
|
||||
// No singleton instance found -> check bean definition.
|
||||
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
|
||||
@@ -904,13 +930,13 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
protected void afterPrototypeCreation(String beanName) {
|
||||
Object curVal = this.prototypesCurrentlyInCreation.get();
|
||||
if (curVal instanceof String) {
|
||||
this.prototypesCurrentlyInCreation.set(null);
|
||||
this.prototypesCurrentlyInCreation.remove();
|
||||
}
|
||||
else if (curVal instanceof Set) {
|
||||
Set<String> beanNameSet = (Set<String>) curVal;
|
||||
beanNameSet.remove(beanName);
|
||||
if (beanNameSet.isEmpty()) {
|
||||
this.prototypesCurrentlyInCreation.set(null);
|
||||
this.prototypesCurrentlyInCreation.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1238,7 +1264,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Class doResolveBeanClass(RootBeanDefinition mbd, Class... typesToMatch) throws ClassNotFoundException {
|
||||
if (!ObjectUtils.isEmpty(typesToMatch)) {
|
||||
ClassLoader tempClassLoader = getTempClassLoader();
|
||||
|
||||
+9
-7
@@ -44,7 +44,6 @@ import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
@@ -467,7 +466,7 @@ class ConstructorResolver {
|
||||
this.beanFactory.logger.trace("Ignoring factory method [" + candidate +
|
||||
"] of bean '" + beanName + "': " + ex);
|
||||
}
|
||||
if (i == candidates.length - 1 && factoryMethodToUse == null) {
|
||||
if (i == candidates.length - 1 && argsHolderToUse == null) {
|
||||
if (causes != null) {
|
||||
for (Exception cause : causes) {
|
||||
this.beanFactory.onSuppressedException(cause);
|
||||
@@ -515,13 +514,13 @@ class ConstructorResolver {
|
||||
}
|
||||
|
||||
if (factoryMethodToUse == null) {
|
||||
boolean hasArgs = resolvedValues.getArgumentCount() > 0;
|
||||
boolean hasArgs = (resolvedValues.getArgumentCount() > 0);
|
||||
String argDesc = "";
|
||||
if (hasArgs) {
|
||||
List<String> argTypes = new ArrayList<String>();
|
||||
for (ValueHolder value : resolvedValues.getIndexedArgumentValues().values()) {
|
||||
String argType = value.getType() != null ?
|
||||
ClassUtils.getShortName(value.getType()) : value.getValue().getClass().getSimpleName();
|
||||
String argType = (value.getType() != null ?
|
||||
ClassUtils.getShortName(value.getType()) : value.getValue().getClass().getSimpleName());
|
||||
argTypes.add(argType);
|
||||
}
|
||||
argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
|
||||
@@ -548,7 +547,7 @@ class ConstructorResolver {
|
||||
ambiguousFactoryMethods);
|
||||
}
|
||||
|
||||
if (explicitArgs == null) {
|
||||
if (explicitArgs == null && argsHolderToUse != null) {
|
||||
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
|
||||
}
|
||||
}
|
||||
@@ -686,15 +685,18 @@ class ConstructorResolver {
|
||||
try {
|
||||
convertedValue = converter.convertIfNecessary(originalValue, paramType,
|
||||
MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex));
|
||||
// TODO re-enable once race condition has been found (SPR-7423)
|
||||
/*
|
||||
if (originalValue == sourceValue || sourceValue instanceof TypedStringValue) {
|
||||
// Either a converted value or still the original one: store converted value.
|
||||
sourceHolder.setConvertedValue(convertedValue);
|
||||
args.preparedArguments[paramIndex] = convertedValue;
|
||||
}
|
||||
else {
|
||||
*/
|
||||
args.resolveNecessary = true;
|
||||
args.preparedArguments[paramIndex] = sourceValue;
|
||||
}
|
||||
// }
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
throw new UnsatisfiedDependencyException(
|
||||
|
||||
+17
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
@@ -541,7 +543,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
|
||||
/**
|
||||
* Considers all beans as eligible for metdata caching
|
||||
* Considers all beans as eligible for metadata caching
|
||||
* if the factory's configuration has been marked as frozen.
|
||||
* @see #freezeConfiguration()
|
||||
*/
|
||||
@@ -554,9 +556,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
if (this.logger.isInfoEnabled()) {
|
||||
this.logger.info("Pre-instantiating singletons in " + this);
|
||||
}
|
||||
|
||||
synchronized (this.beanDefinitionMap) {
|
||||
for (String beanName : this.beanDefinitionNames) {
|
||||
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
|
||||
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
|
||||
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
|
||||
for (String beanName : beanNames) {
|
||||
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
|
||||
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
|
||||
if (isFactoryBean(beanName)) {
|
||||
@@ -570,7 +574,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}, getAccessControlContext());
|
||||
}
|
||||
else {
|
||||
isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit();
|
||||
isEagerInit = (factory instanceof SmartFactoryBean &&
|
||||
((SmartFactoryBean) factory).isEagerInit());
|
||||
}
|
||||
if (isEagerInit) {
|
||||
getBean(beanName);
|
||||
@@ -664,8 +669,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
destroySingleton(beanName);
|
||||
}
|
||||
|
||||
// Reset all bean definitions that have the given bean as parent
|
||||
// (recursively).
|
||||
// Reset all bean definitions that have the given bean as parent (recursively).
|
||||
for (String bdName : this.beanDefinitionNames) {
|
||||
if (!beanName.equals(bdName)) {
|
||||
BeanDefinition bd = this.beanDefinitionMap.get(bdName);
|
||||
@@ -711,7 +715,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
if (value != null) {
|
||||
if (value instanceof String) {
|
||||
String strVal = resolveEmbeddedValue((String) value);
|
||||
BeanDefinition bd = (containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
|
||||
BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
|
||||
value = evaluateBeanDefinitionString(strVal, bd);
|
||||
}
|
||||
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
|
||||
@@ -944,6 +948,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
// Serialization support
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||
throw new NotSerializableException("DefaultListableBeanFactory itself is not deserializable - " +
|
||||
"just a SerializedBeanFactoryReference is");
|
||||
}
|
||||
|
||||
protected Object writeReplace() throws ObjectStreamException {
|
||||
if (this.serializationId != null) {
|
||||
return new SerializedBeanFactoryReference(this.serializationId);
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2010 the original author 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 java.util.Set;
|
||||
*/
|
||||
public class MethodOverrides {
|
||||
|
||||
private final Set<MethodOverride> overrides = new HashSet<MethodOverride>();
|
||||
private final Set<MethodOverride> overrides = new HashSet<MethodOverride>(0);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
+3
-3
@@ -48,11 +48,11 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
|
||||
private final Set<Member> externallyManagedConfigMembers = Collections.synchronizedSet(new HashSet<Member>());
|
||||
private final Set<Member> externallyManagedConfigMembers = Collections.synchronizedSet(new HashSet<Member>(0));
|
||||
|
||||
private final Set<String> externallyManagedInitMethods = Collections.synchronizedSet(new HashSet<String>());
|
||||
private final Set<String> externallyManagedInitMethods = Collections.synchronizedSet(new HashSet<String>(0));
|
||||
|
||||
private final Set<String> externallyManagedDestroyMethods = Collections.synchronizedSet(new HashSet<String>());
|
||||
private final Set<String> externallyManagedDestroyMethods = Collections.synchronizedSet(new HashSet<String>(0));
|
||||
|
||||
private BeanDefinitionHolder decoratedDefinition;
|
||||
|
||||
|
||||
+6
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -1176,7 +1176,10 @@ public class BeanDefinitionParserDelegate {
|
||||
}
|
||||
else {
|
||||
// Child element is what we're looking for.
|
||||
if (valueEle != null) {
|
||||
if (nodeNameEquals(candidateEle, DESCRIPTION_ELEMENT)) {
|
||||
// the element is a <description> -> ignore it
|
||||
}
|
||||
else if (valueEle != null) {
|
||||
error("<entry> element must not contain more than one value sub-element", entryEle);
|
||||
}
|
||||
else {
|
||||
@@ -1422,7 +1425,7 @@ public class BeanDefinitionParserDelegate {
|
||||
/**
|
||||
* Determine whether the name of the supplied node is equal to the supplied name.
|
||||
* <p>The default implementation checks the supplied desired name against both
|
||||
* {@link Node#getNodeName()) and {@link Node#getLocalName()}.
|
||||
* {@link Node#getNodeName()} and {@link Node#getLocalName()}.
|
||||
* <p>Subclasses may override the default implementation to provide a different
|
||||
* mechanism for comparing node names.
|
||||
* @param node the node to compare
|
||||
|
||||
+1
-1
@@ -344,7 +344,7 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
|
||||
finally {
|
||||
currentResources.remove(encodedResource);
|
||||
if (currentResources.isEmpty()) {
|
||||
this.resourcesCurrentlyBeingLoaded.set(null);
|
||||
this.resourcesCurrentlyBeingLoaded.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2010 the original author 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.beans.propertyeditors;
|
||||
import java.beans.PropertyEditorSupport;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -30,6 +31,7 @@ import org.springframework.util.StringUtils;
|
||||
* to the standard {@link Class#forName(String)} method.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ClassArrayEditor extends PropertyEditorSupport {
|
||||
@@ -52,8 +54,7 @@ public class ClassArrayEditor extends PropertyEditorSupport {
|
||||
* (or pass <code>null</code> for the thread context <code>ClassLoader</code>)
|
||||
*/
|
||||
public ClassArrayEditor(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader != null
|
||||
? classLoader : ClassUtils.getDefaultClassLoader();
|
||||
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
|
||||
}
|
||||
|
||||
|
||||
@@ -76,14 +77,9 @@ public class ClassArrayEditor extends PropertyEditorSupport {
|
||||
@Override
|
||||
public String getAsText() {
|
||||
Class[] classes = (Class[]) getValue();
|
||||
if (classes == null || classes.length == 0) {
|
||||
if (ObjectUtils.isEmpty(classes)) {
|
||||
return "";
|
||||
}
|
||||
return toCommaDelimitedString(classes);
|
||||
}
|
||||
|
||||
|
||||
private static String toCommaDelimitedString(Class[] classes) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < classes.length; ++i) {
|
||||
if (i > 0) {
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -53,8 +53,7 @@ public class ClassEditor extends PropertyEditorSupport {
|
||||
* (or <code>null</code> for the thread context ClassLoader)
|
||||
*/
|
||||
public ClassEditor(ClassLoader classLoader) {
|
||||
this.classLoader =
|
||||
(classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
|
||||
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author 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,10 +34,6 @@ public class CurrencyEditor extends PropertyEditorSupport {
|
||||
setValue(Currency.getInstance(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns <code>null</code> to indicate that
|
||||
* there is no appropriate text representation.
|
||||
*/
|
||||
@Override
|
||||
public String getAsText() {
|
||||
Currency value = (Currency) getValue();
|
||||
|
||||
+5
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -77,7 +77,10 @@ public class CustomDateEditor extends PropertyEditorSupport {
|
||||
* thrown if the String does not exactly match the length specified. This is useful
|
||||
* because SimpleDateFormat does not enforce strict parsing of the year part,
|
||||
* not even with <code>setLenient(false)</code>. Without an "exactDateLength"
|
||||
* specified, the "01/01/05" would get parsed to "01/01/0005".
|
||||
* specified, the "01/01/05" would get parsed to "01/01/0005". However, even
|
||||
* with an "exactDateLength" specified, prepended zeros in the day or month
|
||||
* part may still allow for a shorter year part, so consider this as just
|
||||
* one more assertion that gets you closer to the intended date format.
|
||||
* @param dateFormat DateFormat to use for parsing and rendering
|
||||
* @param allowEmpty if empty strings should be allowed
|
||||
* @param exactDateLength the exact expected length of the date String
|
||||
|
||||
+6
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,12 +27,14 @@ import org.xml.sax.InputSource;
|
||||
import org.springframework.beans.PropertyEditorRegistrar;
|
||||
import org.springframework.beans.PropertyEditorRegistry;
|
||||
import org.springframework.beans.PropertyEditorRegistrySupport;
|
||||
import org.springframework.beans.propertyeditors.ClassArrayEditor;
|
||||
import org.springframework.beans.propertyeditors.ClassEditor;
|
||||
import org.springframework.beans.propertyeditors.FileEditor;
|
||||
import org.springframework.beans.propertyeditors.InputSourceEditor;
|
||||
import org.springframework.beans.propertyeditors.InputStreamEditor;
|
||||
import org.springframework.beans.propertyeditors.URIEditor;
|
||||
import org.springframework.beans.propertyeditors.URLEditor;
|
||||
import org.springframework.core.io.ContextResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceEditor;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
@@ -83,14 +85,16 @@ public class ResourceEditorRegistrar implements PropertyEditorRegistrar {
|
||||
public void registerCustomEditors(PropertyEditorRegistry registry) {
|
||||
ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader);
|
||||
doRegisterEditor(registry, Resource.class, baseEditor);
|
||||
doRegisterEditor(registry, ContextResource.class, baseEditor);
|
||||
doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
|
||||
doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
|
||||
doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
|
||||
doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));
|
||||
|
||||
ClassLoader classLoader = this.resourceLoader.getClassLoader();
|
||||
doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
|
||||
doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
|
||||
doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
|
||||
doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));
|
||||
|
||||
if (this.resourceLoader instanceof ResourcePatternResolver) {
|
||||
doRegisterEditor(registry, Resource[].class,
|
||||
|
||||
+5
-5
@@ -864,7 +864,7 @@
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="listOrSetType">
|
||||
<xsd:attribute name="merge" type="defaultable-boolean">
|
||||
<xsd:attribute name="merge" default="default" type="defaultable-boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Enables/disables merging for collections when using parent/child beans.
|
||||
@@ -887,7 +887,7 @@
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="listOrSetType">
|
||||
<xsd:attribute name="merge" type="defaultable-boolean">
|
||||
<xsd:attribute name="merge" default="default" type="defaultable-boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Enables/disables merging for collections when using parent/child beans.
|
||||
@@ -908,7 +908,7 @@
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="listOrSetType">
|
||||
<xsd:attribute name="merge" type="defaultable-boolean">
|
||||
<xsd:attribute name="merge" default="default" type="defaultable-boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Enables/disables merging for collections when using parent/child beans.
|
||||
@@ -929,7 +929,7 @@
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="mapType">
|
||||
<xsd:attribute name="merge" type="defaultable-boolean">
|
||||
<xsd:attribute name="merge" default="default" type="defaultable-boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Enables/disables merging for collections when using parent/child beans.
|
||||
@@ -960,7 +960,7 @@
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="propsType">
|
||||
<xsd:attribute name="merge" type="defaultable-boolean">
|
||||
<xsd:attribute name="merge" default="default" type="defaultable-boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Enables/disables merging for collections when using parent/child beans.
|
||||
|
||||
+18
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author 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,10 +19,11 @@ package org.springframework.beans;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
@@ -117,6 +118,19 @@ public class BeanWrapperAutoGrowingTests {
|
||||
assertNotNull(wrapper.getPropertyValue("list[3]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPropertyValueAutoGrowListFailsAgainstLimit() {
|
||||
wrapper.setAutoGrowCollectionLimit(2);
|
||||
try {
|
||||
assertNotNull(wrapper.getPropertyValue("list[4]"));
|
||||
fail("Should have thrown InvalidPropertyException");
|
||||
}
|
||||
catch (InvalidPropertyException ex) {
|
||||
// expected
|
||||
assertTrue(ex.getRootCause() instanceof IndexOutOfBoundsException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPropertyValueAutoGrowMultiDimensionalList() {
|
||||
assertNotNull(wrapper.getPropertyValue("multiList[0][0]"));
|
||||
@@ -129,17 +143,10 @@ public class BeanWrapperAutoGrowingTests {
|
||||
wrapper.getPropertyValue("listNotParameterized[0]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPropertyValueAutoGrowMap() {
|
||||
assertNotNull(wrapper.getPropertyValue("map[A]"));
|
||||
assertEquals(1, bean.getMap().size());
|
||||
assertTrue(bean.getMap().get("A") instanceof Bean);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPropertyValueAutoGrowMap() {
|
||||
wrapper.setPropertyValue("map[A].prop", "test");
|
||||
assertEquals("test", bean.getMap().get("A").getProp());
|
||||
wrapper.setPropertyValue("map[A]", new Bean());
|
||||
assertTrue(bean.getMap().get("A") instanceof Bean);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
@@ -36,6 +36,7 @@ import javax.security.auth.Subject;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import test.beans.DerivedTestBean;
|
||||
import test.beans.DummyFactory;
|
||||
@@ -1752,6 +1753,7 @@ public class DefaultListableBeanFactoryTests {
|
||||
*/
|
||||
|
||||
@Test
|
||||
@Ignore // TODO re-enable when ConstructorResolver TODO sorted out
|
||||
public void testPrototypeCreationWithConstructorArgumentsIsFastEnough() {
|
||||
if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) {
|
||||
// Skip this test: Trace logging blows the time limit.
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package org.springframework.beans.factory.config;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
|
||||
import test.beans.TestBean;
|
||||
|
||||
/**
|
||||
* Tests cornering SPR-7547.
|
||||
*
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public class PropertyPlaceholderConfigurerTests {
|
||||
|
||||
/**
|
||||
* Prior to the fix for SPR-7547, the following would throw
|
||||
* IllegalStateException because the PropertiesLoaderSupport base class
|
||||
* assumed ByteArrayResource implements Resource.getFilename(). It does
|
||||
* not, and AbstractResource.getFilename() is called instead, raising the
|
||||
* exception. The following now works, as getFilename() is called in a
|
||||
* try/catch to check whether the resource is actually file-based or not.
|
||||
*
|
||||
* See SPR-7552, which suggests paths to address the root issue rather than
|
||||
* just patching the problem.
|
||||
*/
|
||||
@Test
|
||||
public void repro() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.registerBeanDefinition("testBean",
|
||||
rootBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${my.name}").getBeanDefinition());
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
ppc.setLocation(new ByteArrayResource("my.name=Inigo Montoya".getBytes()));
|
||||
ppc.postProcessBeanFactory(bf);
|
||||
|
||||
TestBean testBean = bf.getBean(TestBean.class);
|
||||
assertThat(testBean.getName(), equalTo("Inigo Montoya"));
|
||||
}
|
||||
}
|
||||
+12
@@ -155,6 +155,18 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- The <description> element below caused parsing exception prior to resolution of SPR-8563 -->
|
||||
<bean id="mapWithDescriptionInEntry" class="org.springframework.beans.factory.xml.HasMap">
|
||||
<property name="map">
|
||||
<map>
|
||||
<entry key="e1">
|
||||
<description>A map entry with a description</description>
|
||||
<value>v1</value>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="fooKey" class="java.lang.String">
|
||||
<constructor-arg value="foo"/>
|
||||
</bean>
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
<publications>
|
||||
<artifact name="${ant.project.name}"/>
|
||||
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
|
||||
<artifact name="license" type="license" ext="txt"/>
|
||||
<artifact name="notice" type="notice" ext="txt"/>
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
@@ -49,7 +51,7 @@
|
||||
<dependency org="org.hsqldb" name="com.springsource.org.hsqldb" rev="1.8.0.9" conf="test->runtime"/>
|
||||
<dependency org="org.apache.poi" name="com.springsource.org.apache.poi" rev="3.0.2.FINAL" conf="test->compile"/>
|
||||
<dependency org="org.easymock" name="com.springsource.org.easymock" rev="2.5.1" conf="test->compile"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${org.junit.version}" conf="test->runtime"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->runtime"/>
|
||||
</dependencies>
|
||||
|
||||
</ivy-module>
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.0.4.BUILD-SNAPSHOT</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.0.4.BUILD-SNAPSHOT</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
|
||||
|
||||
+9
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.cache.ehcache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import net.sf.ehcache.CacheException;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
@@ -97,23 +98,17 @@ public class EhCacheManagerFactoryBean implements FactoryBean<CacheManager>, Ini
|
||||
|
||||
public void afterPropertiesSet() throws IOException, CacheException {
|
||||
logger.info("Initializing EHCache CacheManager");
|
||||
if (this.shared) {
|
||||
// Shared CacheManager singleton at the VM level.
|
||||
if (this.configLocation != null) {
|
||||
this.cacheManager = CacheManager.create(this.configLocation.getInputStream());
|
||||
if (this.configLocation != null) {
|
||||
InputStream is = this.configLocation.getInputStream();
|
||||
try {
|
||||
this.cacheManager = (this.shared ? CacheManager.create(is) : new CacheManager(is));
|
||||
}
|
||||
else {
|
||||
this.cacheManager = CacheManager.create();
|
||||
finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Independent CacheManager instance (the default).
|
||||
if (this.configLocation != null) {
|
||||
this.cacheManager = new CacheManager(this.configLocation.getInputStream());
|
||||
}
|
||||
else {
|
||||
this.cacheManager = new CacheManager();
|
||||
}
|
||||
this.cacheManager = (this.shared ? CacheManager.create() : new CacheManager());
|
||||
}
|
||||
if (this.cacheManagerName != null) {
|
||||
this.cacheManager.setName(this.cacheManagerName);
|
||||
|
||||
+8
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,6 +40,13 @@ public class LocalTaskExecutorThreadPool implements ThreadPool {
|
||||
private Executor taskExecutor;
|
||||
|
||||
|
||||
public void setInstanceId(String schedInstId) {
|
||||
}
|
||||
|
||||
public void setInstanceName(String schedName) {
|
||||
}
|
||||
|
||||
|
||||
public void initialize() throws SchedulerConfigException {
|
||||
// Absolutely needs thread-bound TaskExecutor to initialize.
|
||||
this.taskExecutor = SchedulerFactoryBean.getConfigTimeTaskExecutor();
|
||||
|
||||
+21
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
@@ -34,7 +35,6 @@ import org.quartz.SchedulerListener;
|
||||
import org.quartz.Trigger;
|
||||
import org.quartz.TriggerListener;
|
||||
import org.quartz.spi.ClassLoadHelper;
|
||||
import org.quartz.xml.JobSchedulingDataProcessor;
|
||||
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
@@ -240,9 +240,25 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
if (this.jobSchedulingDataLocations != null) {
|
||||
ClassLoadHelper clh = new ResourceLoaderClassLoadHelper(this.resourceLoader);
|
||||
clh.initialize();
|
||||
JobSchedulingDataProcessor dataProcessor = new JobSchedulingDataProcessor(clh, true, true);
|
||||
for (String location : this.jobSchedulingDataLocations) {
|
||||
dataProcessor.processFileAndScheduleJobs(location, getScheduler(), this.overwriteExistingJobs);
|
||||
try {
|
||||
// Quartz 1.8 or higher?
|
||||
Class dataProcessorClass = getClass().getClassLoader().loadClass("org.quartz.xml.XMLSchedulingDataProcessor");
|
||||
logger.debug("Using Quartz 1.8 XMLSchedulingDataProcessor");
|
||||
Object dataProcessor = dataProcessorClass.getConstructor(ClassLoadHelper.class).newInstance(clh);
|
||||
Method processFileAndScheduleJobs = dataProcessorClass.getMethod("processFileAndScheduleJobs", String.class, Scheduler.class);
|
||||
for (String location : this.jobSchedulingDataLocations) {
|
||||
processFileAndScheduleJobs.invoke(dataProcessor, location, getScheduler());
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Quartz 1.6
|
||||
Class dataProcessorClass = getClass().getClassLoader().loadClass("org.quartz.xml.JobSchedulingDataProcessor");
|
||||
logger.debug("Using Quartz 1.6 JobSchedulingDataProcessor");
|
||||
Object dataProcessor = dataProcessorClass.getConstructor(ClassLoadHelper.class, boolean.class, boolean.class).newInstance(clh, true, true);
|
||||
Method processFileAndScheduleJobs = dataProcessorClass.getMethod("processFileAndScheduleJobs", String.class, Scheduler.class, boolean.class);
|
||||
for (String location : this.jobSchedulingDataLocations) {
|
||||
processFileAndScheduleJobs.invoke(dataProcessor, location, getScheduler(), this.overwriteExistingJobs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author 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,9 +74,9 @@ 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><b>Note:</b> This version of Spring's SchedulerFactoryBean requires
|
||||
* Quartz 1.5.x or 1.6.x. The "jobSchedulingDataLocation" feature requires
|
||||
* Quartz 1.6.1 or higher (as of Spring 2.5.5).
|
||||
* <p><b>Note:</b> This version of Spring's SchedulerFactoryBean supports Quartz 1.x,
|
||||
* more specifically Quartz 1.5 or higher. The "jobSchedulingDataLocation" feature
|
||||
* requires Quartz 1.6.1 or higher (as of Spring 2.5.5).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 18.02.2004
|
||||
@@ -496,16 +496,16 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
|
||||
finally {
|
||||
if (this.resourceLoader != null) {
|
||||
configTimeResourceLoaderHolder.set(null);
|
||||
configTimeResourceLoaderHolder.remove();
|
||||
}
|
||||
if (this.taskExecutor != null) {
|
||||
configTimeTaskExecutorHolder.set(null);
|
||||
configTimeTaskExecutorHolder.remove();
|
||||
}
|
||||
if (this.dataSource != null) {
|
||||
configTimeDataSourceHolder.set(null);
|
||||
configTimeDataSourceHolder.remove();
|
||||
}
|
||||
if (this.nonTransactionalDataSource != null) {
|
||||
configTimeNonTransactionalDataSourceHolder.set(null);
|
||||
configTimeNonTransactionalDataSourceHolder.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
<publications>
|
||||
<artifact name="${ant.project.name}"/>
|
||||
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
|
||||
<artifact name="license" type="license" ext="txt"/>
|
||||
<artifact name="notice" type="notice" ext="txt"/>
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
@@ -63,7 +65,7 @@
|
||||
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.dbcp" rev="1.2.2.osgi" conf="test->runtime"/>
|
||||
<dependency org="org.apache.log4j" name="com.springsource.org.apache.log4j" rev="1.2.15" conf="test->runtime"/>
|
||||
<dependency org="org.easymock" name="com.springsource.org.easymock" rev="2.5.1" conf="test->compile"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${org.junit.version}" conf="test->runtime"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->runtime"/>
|
||||
<dependency org="org.slf4j" name="com.springsource.slf4j.jcl" rev="${slf4j.version}" conf="test->runtime"/>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.0.4.BUILD-SNAPSHOT</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.0.4.BUILD-SNAPSHOT</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author 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 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
|
||||
|
||||
/**
|
||||
* Create a new AnnotationConfigApplicationContext that needs to be populated
|
||||
* through {@link #add} calls and then manually {@link #refresh refreshed}.
|
||||
* through {@link #register} calls and then manually {@link #refresh refreshed}.
|
||||
*/
|
||||
public AnnotationConfigApplicationContext() {
|
||||
}
|
||||
|
||||
+37
-35
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author 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,6 +58,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.jndi.support.SimpleJndiBeanFactory;
|
||||
@@ -303,7 +304,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
}
|
||||
|
||||
|
||||
private InjectionMetadata findResourceMetadata(final Class clazz) {
|
||||
private InjectionMetadata findResourceMetadata(final Class<?> clazz) {
|
||||
// Quick check on the concurrent map first, with minimal locking.
|
||||
InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);
|
||||
if (metadata == null) {
|
||||
@@ -338,40 +339,41 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
}
|
||||
}
|
||||
for (Method method : targetClass.getDeclaredMethods()) {
|
||||
if (webServiceRefClass != null && method.isAnnotationPresent(webServiceRefClass) &&
|
||||
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
|
||||
}
|
||||
if (method.getParameterTypes().length != 1) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
|
||||
}
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
|
||||
currElements.add(new WebServiceRefElement(method, pd));
|
||||
}
|
||||
else if (ejbRefClass != null && method.isAnnotationPresent(ejbRefClass) &&
|
||||
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@EJB annotation is not supported on static methods");
|
||||
}
|
||||
if (method.getParameterTypes().length != 1) {
|
||||
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
|
||||
}
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
|
||||
currElements.add(new EjbRefElement(method, pd));
|
||||
}
|
||||
else if (method.isAnnotationPresent(Resource.class) &&
|
||||
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@Resource annotation is not supported on static methods");
|
||||
}
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
if (paramTypes.length != 1) {
|
||||
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
|
||||
}
|
||||
if (!ignoredResourceTypes.contains(paramTypes[0].getName())) {
|
||||
method = BridgeMethodResolver.findBridgedMethod(method);
|
||||
Method mostSpecificMethod = BridgeMethodResolver.findBridgedMethod(ClassUtils.getMostSpecificMethod(method, clazz));
|
||||
if (method.equals(mostSpecificMethod)) {
|
||||
if (webServiceRefClass != null && method.isAnnotationPresent(webServiceRefClass)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
|
||||
}
|
||||
if (method.getParameterTypes().length != 1) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
|
||||
}
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
|
||||
currElements.add(new ResourceElement(method, pd));
|
||||
currElements.add(new WebServiceRefElement(method, pd));
|
||||
}
|
||||
else if (ejbRefClass != null && method.isAnnotationPresent(ejbRefClass)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@EJB annotation is not supported on static methods");
|
||||
}
|
||||
if (method.getParameterTypes().length != 1) {
|
||||
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
|
||||
}
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
|
||||
currElements.add(new EjbRefElement(method, pd));
|
||||
}
|
||||
else if (method.isAnnotationPresent(Resource.class)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@Resource annotation is not supported on static methods");
|
||||
}
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
if (paramTypes.length != 1) {
|
||||
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
|
||||
}
|
||||
if (!ignoredResourceTypes.contains(paramTypes[0].getName())) {
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
|
||||
currElements.add(new ResourceElement(method, pd));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -107,8 +107,7 @@ final class ConfigurationClass {
|
||||
|
||||
|
||||
public void validate(ProblemReporter problemReporter) {
|
||||
|
||||
// a @Bean method may only be overloaded through inheritance. No single
|
||||
// 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>();
|
||||
@@ -134,9 +133,10 @@ final class ConfigurationClass {
|
||||
if (getMetadata().isFinal()) {
|
||||
problemReporter.error(new FinalConfigurationProblem());
|
||||
}
|
||||
for (ConfigurationClassMethod method : this.methods) {
|
||||
method.validate(problemReporter);
|
||||
}
|
||||
}
|
||||
|
||||
for (ConfigurationClassMethod method : this.methods) {
|
||||
method.validate(problemReporter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +152,10 @@ final class ConfigurationClass {
|
||||
return getMetadata().getClassName().hashCode();
|
||||
}
|
||||
|
||||
/** Configuration classes must be non-final to accommodate CGLIB subclassing. */
|
||||
|
||||
/**
|
||||
* Configuration classes must be non-final to accommodate CGLIB subclassing.
|
||||
*/
|
||||
private class FinalConfigurationProblem extends Problem {
|
||||
|
||||
public FinalConfigurationProblem() {
|
||||
@@ -161,7 +164,10 @@ final class ConfigurationClass {
|
||||
}
|
||||
}
|
||||
|
||||
/** Bean methods on configuration classes may only be overloaded through inheritance. */
|
||||
|
||||
/**
|
||||
* Bean methods on configuration classes may only be overloaded through inheritance.
|
||||
*/
|
||||
private class BeanMethodOverloadingProblem extends Problem {
|
||||
|
||||
public BeanMethodOverloadingProblem(String methodName, int count) {
|
||||
@@ -171,5 +177,4 @@ final class ConfigurationClass {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+3
-5
@@ -118,11 +118,9 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
*/
|
||||
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass) {
|
||||
doLoadBeanDefinitionForConfigurationClassIfNecessary(configClass);
|
||||
|
||||
for (ConfigurationClassMethod method : configClass.getMethods()) {
|
||||
loadBeanDefinitionsForModelMethod(method);
|
||||
}
|
||||
|
||||
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
|
||||
}
|
||||
|
||||
@@ -139,7 +137,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
GenericBeanDefinition configBeanDef = new GenericBeanDefinition();
|
||||
String className = configClass.getMetadata().getClassName();
|
||||
configBeanDef.setBeanClassName(className);
|
||||
if(checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) {
|
||||
if (checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) {
|
||||
String configBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName(configBeanDef, this.registry);
|
||||
configClass.setBeanName(configBeanName);
|
||||
if (logger.isDebugEnabled()) {
|
||||
@@ -160,8 +158,8 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a particular {@link ConfigurationClassMethod}, registering bean definitions with
|
||||
* the BeanDefinitionRegistry based on its contents.
|
||||
* Reads a particular {@link ConfigurationClassMethod}, registering bean definitions
|
||||
* with the BeanDefinitionRegistry based on its contents.
|
||||
*/
|
||||
private void loadBeanDefinitionsForModelMethod(ConfigurationClassMethod method) {
|
||||
ConfigurationClass configClass = method.getConfigurationClass();
|
||||
|
||||
+23
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import org.springframework.beans.factory.parsing.Location;
|
||||
import org.springframework.beans.factory.parsing.Problem;
|
||||
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||
@@ -54,18 +52,25 @@ final class ConfigurationClassMethod {
|
||||
}
|
||||
|
||||
public Location getResourceLocation() {
|
||||
return new Location(this.configurationClass.getResource(), metadata);
|
||||
return new Location(this.configurationClass.getResource(), this.metadata);
|
||||
}
|
||||
|
||||
public void validate(ProblemReporter problemReporter) {
|
||||
if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName()) && !getMetadata().isOverridable()) {
|
||||
problemReporter.error(new NonOverridableMethodError());
|
||||
if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) {
|
||||
if (!getMetadata().isOverridable()) {
|
||||
problemReporter.error(new NonOverridableMethodError());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (getMetadata().isStatic()) {
|
||||
problemReporter.error(new StaticMethodError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return format("[%s:name=%s,declaringClass=%s]",
|
||||
return String.format("[%s:name=%s,declaringClass=%s]",
|
||||
this.getClass().getSimpleName(), this.getMetadata().getMethodName(), this.getMetadata().getDeclaringClassName());
|
||||
}
|
||||
|
||||
@@ -82,4 +87,15 @@ final class ConfigurationClassMethod {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link Bean} methods must at least not be static in the non-CGLIB case.
|
||||
*/
|
||||
private class StaticMethodError extends Problem {
|
||||
|
||||
public StaticMethodError() {
|
||||
super(String.format("Method '%s' must not be static; remove the method's static modifier to continue",
|
||||
getMetadata().getMethodName()), getResourceLocation());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -139,8 +139,8 @@ class ConfigurationClassParser {
|
||||
}
|
||||
}
|
||||
Set<MethodMetadata> beanMethods = metadata.getAnnotatedMethods(Bean.class.getName());
|
||||
for (MethodMetadata methodMetadata : beanMethods) {
|
||||
configClass.addMethod(new ConfigurationClassMethod(methodMetadata, configClass));
|
||||
for (MethodMetadata beanMethod : beanMethods) {
|
||||
configClass.addMethod(new ConfigurationClassMethod(beanMethod, configClass));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
@@ -80,9 +81,9 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
|
||||
private boolean setMetadataReaderFactoryCalled = false;
|
||||
|
||||
private boolean postProcessBeanDefinitionRegistryCalled = false;
|
||||
private final Set<Integer> registriesPostProcessed = new HashSet<Integer>();
|
||||
|
||||
private boolean postProcessBeanFactoryCalled = false;
|
||||
private final Set<Integer> factoriesPostProcessed = new HashSet<Integer>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -130,15 +131,16 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
* Derive further bean definitions from the configuration classes in the registry.
|
||||
*/
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
|
||||
if (this.postProcessBeanDefinitionRegistryCalled) {
|
||||
int registryId = System.identityHashCode(registry);
|
||||
if (this.registriesPostProcessed.contains(registryId)) {
|
||||
throw new IllegalStateException(
|
||||
"postProcessBeanDefinitionRegistry already called for this post-processor");
|
||||
"postProcessBeanDefinitionRegistry already called for this post-processor against " + registry);
|
||||
}
|
||||
if (this.postProcessBeanFactoryCalled) {
|
||||
if (this.factoriesPostProcessed.contains(registryId)) {
|
||||
throw new IllegalStateException(
|
||||
"postProcessBeanFactory already called for this post-processor");
|
||||
"postProcessBeanFactory already called for this post-processor against " + registry);
|
||||
}
|
||||
this.postProcessBeanDefinitionRegistryCalled = true;
|
||||
this.registriesPostProcessed.add(registryId);
|
||||
processConfigBeanDefinitions(registry);
|
||||
}
|
||||
|
||||
@@ -147,12 +149,13 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
* by replacing them with CGLIB-enhanced subclasses.
|
||||
*/
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
if (this.postProcessBeanFactoryCalled) {
|
||||
int factoryId = System.identityHashCode(beanFactory);
|
||||
if (this.factoriesPostProcessed.contains(factoryId)) {
|
||||
throw new IllegalStateException(
|
||||
"postProcessBeanFactory already called for this post-processor");
|
||||
"postProcessBeanFactory already called for this post-processor against " + beanFactory);
|
||||
}
|
||||
this.postProcessBeanFactoryCalled = true;
|
||||
if (!this.postProcessBeanDefinitionRegistryCalled) {
|
||||
this.factoriesPostProcessed.add((factoryId));
|
||||
if (!this.registriesPostProcessed.contains((factoryId))) {
|
||||
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
|
||||
// Simply call processConfigBeanDefinitions lazily at this point then.
|
||||
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -53,7 +53,7 @@ abstract class AbstractPropertyLoadingBeanDefinitionParser extends AbstractSingl
|
||||
|
||||
String fileEncoding = element.getAttribute("file-encoding");
|
||||
if (StringUtils.hasLength(fileEncoding)) {
|
||||
builder.addPropertyReference("fileEncoding", fileEncoding);
|
||||
builder.addPropertyValue("fileEncoding", fileEncoding);
|
||||
}
|
||||
|
||||
String order = element.getAttribute("order");
|
||||
|
||||
+1
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,12 +38,9 @@ class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBea
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, BeanDefinitionBuilder builder) {
|
||||
|
||||
super.doParse(element, builder);
|
||||
|
||||
builder.addPropertyValue("ignoreUnresolvablePlaceholders",
|
||||
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
|
||||
|
||||
String systemPropertiesModeName = element.getAttribute("system-properties-mode");
|
||||
if (StringUtils.hasLength(systemPropertiesModeName)) {
|
||||
builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_"+systemPropertiesModeName);
|
||||
|
||||
+1
-1
@@ -238,7 +238,7 @@ public abstract class AbstractApplicationEventMulticaster implements Application
|
||||
BeanFactory beanFactory = getBeanFactory();
|
||||
for (String listenerBeanName : this.applicationListenerBeans) {
|
||||
ApplicationListener listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
|
||||
if (!this.preFiltered && !allListeners.contains(listener)) {
|
||||
if (this.preFiltered || !allListeners.contains(listener)) {
|
||||
allListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
+33
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author 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,11 +34,17 @@ import org.springframework.expression.TypedValue;
|
||||
public class MapAccessor implements PropertyAccessor {
|
||||
|
||||
public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return (((Map) target).containsKey(name));
|
||||
Map map = (Map) target;
|
||||
return map.containsKey(name);
|
||||
}
|
||||
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return new TypedValue(((Map) target).get(name));
|
||||
Map map = (Map) target;
|
||||
Object value = map.get(name);
|
||||
if (value == null && !map.containsKey(name)) {
|
||||
throw new MapAccessException(name);
|
||||
}
|
||||
return new TypedValue(value);
|
||||
}
|
||||
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
@@ -47,11 +53,32 @@ public class MapAccessor implements PropertyAccessor {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
|
||||
((Map) target).put(name, newValue);
|
||||
Map map = (Map) target;
|
||||
map.put(name, newValue);
|
||||
}
|
||||
|
||||
public Class[] getSpecificTargetClasses() {
|
||||
return new Class[] { Map.class };
|
||||
return new Class[] {Map.class};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Exception thrown from <code>read</code> in order to reset a cached
|
||||
* PropertyAccessor, allowing other accessors to have a try.
|
||||
*/
|
||||
private static class MapAccessException extends AccessException {
|
||||
|
||||
private final String key;
|
||||
|
||||
public MapAccessException(String key) {
|
||||
super(null);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "Map does not contain a value for key '" + this.key + "'";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+18
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author 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,8 @@ import org.springframework.core.NamedThreadLocal;
|
||||
/**
|
||||
* Simple holder class that associates a LocaleContext instance
|
||||
* with the current thread. The LocaleContext will be inherited
|
||||
* by any child threads spawned by the current thread.
|
||||
* by any child threads spawned by the current thread if the
|
||||
* <code>inheritable<code> flag is set to <code>true</code>.
|
||||
*
|
||||
* <p>Used as a central holder for the current Locale in Spring,
|
||||
* wherever necessary: for example, in MessageSourceAccessor.
|
||||
@@ -51,15 +52,14 @@ public abstract class LocaleContextHolder {
|
||||
* Reset the LocaleContext for the current thread.
|
||||
*/
|
||||
public static void resetLocaleContext() {
|
||||
localeContextHolder.set(null);
|
||||
inheritableLocaleContextHolder.set(null);
|
||||
localeContextHolder.remove();
|
||||
inheritableLocaleContextHolder.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the given LocaleContext with the current thread,
|
||||
* <i>not</i> exposing it as inheritable for child threads.
|
||||
* @param localeContext the current LocaleContext, or <code>null</code> to reset
|
||||
* the thread-bound context
|
||||
* @param localeContext the current LocaleContext
|
||||
*/
|
||||
public static void setLocaleContext(LocaleContext localeContext) {
|
||||
setLocaleContext(localeContext, false);
|
||||
@@ -67,19 +67,24 @@ public abstract class LocaleContextHolder {
|
||||
|
||||
/**
|
||||
* Associate the given LocaleContext with the current thread.
|
||||
* @param localeContext the current LocaleContext, or <code>null</code> to reset
|
||||
* the thread-bound context
|
||||
* @param localeContext the current LocaleContext,
|
||||
* or <code>null</code> to reset the thread-bound context
|
||||
* @param inheritable whether to expose the LocaleContext as inheritable
|
||||
* for child threads (using an {@link java.lang.InheritableThreadLocal})
|
||||
*/
|
||||
public static void setLocaleContext(LocaleContext localeContext, boolean inheritable) {
|
||||
if (inheritable) {
|
||||
inheritableLocaleContextHolder.set(localeContext);
|
||||
localeContextHolder.set(null);
|
||||
if (localeContext == null) {
|
||||
resetLocaleContext();
|
||||
}
|
||||
else {
|
||||
localeContextHolder.set(localeContext);
|
||||
inheritableLocaleContextHolder.set(null);
|
||||
if (inheritable) {
|
||||
inheritableLocaleContextHolder.set(localeContext);
|
||||
localeContextHolder.remove();
|
||||
}
|
||||
else {
|
||||
localeContextHolder.set(localeContext);
|
||||
inheritableLocaleContextHolder.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -1326,11 +1326,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
if (!(bean instanceof BeanPostProcessor) &&
|
||||
if (bean != null && !(bean instanceof BeanPostProcessor) &&
|
||||
this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Bean '" + beanName + "' is not eligible for getting processed by all " +
|
||||
"BeanPostProcessors (for example: not eligible for auto-proxying)");
|
||||
logger.info("Bean '" + beanName + "' of type [" + bean.getClass() +
|
||||
"] is not eligible for getting processed by all BeanPostProcessors " +
|
||||
"(for example: not eligible for auto-proxying)");
|
||||
}
|
||||
}
|
||||
return bean;
|
||||
|
||||
+8
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author 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,10 +34,11 @@ import org.springframework.util.StringValueResolver;
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor}
|
||||
* implementation that passes the ApplicationContext to beans that
|
||||
* implement the {@link ResourceLoaderAware}, {@link MessageSourceAware},
|
||||
* {@link ApplicationEventPublisherAware} and/or
|
||||
* implement the {@link EmbeddedValueResolverAware}, {@link ResourceLoaderAware},
|
||||
* {@link MessageSourceAware}, {@link ApplicationEventPublisherAware} and/or
|
||||
* {@link ApplicationContextAware} interfaces.
|
||||
* If all of them are implemented, they are satisfied in the given order.
|
||||
*
|
||||
* <p>Implemented interfaces are satisfied in order of their mention above.
|
||||
*
|
||||
* <p>Application contexts will automatically register this with their
|
||||
* underlying bean factory. Applications do not use this directly.
|
||||
@@ -45,6 +46,7 @@ import org.springframework.util.StringValueResolver;
|
||||
* @author Juergen Hoeller
|
||||
* @author Costin Leau
|
||||
* @since 10.10.2003
|
||||
* @see org.springframework.context.EmbeddedValueResolverAware
|
||||
* @see org.springframework.context.ResourceLoaderAware
|
||||
* @see org.springframework.context.MessageSourceAware
|
||||
* @see org.springframework.context.ApplicationEventPublisherAware
|
||||
@@ -68,7 +70,8 @@ class ApplicationContextAwareProcessor implements BeanPostProcessor {
|
||||
AccessControlContext acc = null;
|
||||
|
||||
if (System.getSecurityManager() != null &&
|
||||
(bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
|
||||
(bean instanceof EmbeddedValueResolverAware ||
|
||||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
|
||||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
|
||||
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
|
||||
}
|
||||
|
||||
+8
-2
@@ -18,6 +18,7 @@ package org.springframework.context.support;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver;
|
||||
@@ -99,7 +100,6 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
|
||||
*/
|
||||
public GenericApplicationContext() {
|
||||
this.beanFactory = new DefaultListableBeanFactory();
|
||||
this.beanFactory.setSerializationId(getId());
|
||||
this.beanFactory.setParameterNameDiscoverer(new LocalVariableTableParameterNameDiscoverer());
|
||||
this.beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
||||
}
|
||||
@@ -153,7 +153,6 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
|
||||
@Override
|
||||
public void setId(String id) {
|
||||
super.setId(id);
|
||||
this.beanFactory.setSerializationId(id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,9 +242,16 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
|
||||
throw new IllegalStateException(
|
||||
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
|
||||
}
|
||||
this.beanFactory.setSerializationId(getId());
|
||||
this.refreshed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancelRefresh(BeansException ex) {
|
||||
this.beanFactory.setSerializationId(null);
|
||||
super.cancelRefresh(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not much to do: We hold a single internal BeanFactory that will never
|
||||
* get released.
|
||||
|
||||
+27
@@ -17,6 +17,7 @@
|
||||
package org.springframework.context.support;
|
||||
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
@@ -30,6 +31,7 @@ import org.springframework.core.io.Resource;
|
||||
* deliberately override certain bean definitions via an extra configuration file.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @since 3.0
|
||||
* @see #load
|
||||
* @see XmlBeanDefinitionReader
|
||||
@@ -67,6 +69,17 @@ public class GenericXmlApplicationContext extends GenericApplicationContext {
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new GenericXmlApplicationContext, loading bean definitions
|
||||
* from the given resource locations and automatically refreshing the context.
|
||||
* @param relativeClass class whose package will be used as a prefix when
|
||||
* loading each specified resource name
|
||||
* @param resourceNames relatively-qualified names of resources to load
|
||||
*/
|
||||
public GenericXmlApplicationContext(Class<?> relativeClass, String... resourceNames) {
|
||||
load(relativeClass, resourceNames);
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use XML validation. Default is <code>true</code>.
|
||||
@@ -92,4 +105,18 @@ public class GenericXmlApplicationContext extends GenericApplicationContext {
|
||||
this.reader.loadBeanDefinitions(resourceLocations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load bean definitions from the given XML resources.
|
||||
* @param relativeClass class whose package will be used as a prefix when
|
||||
* loading each specified resource name
|
||||
* @param resourceNames relatively-qualified names of resources to load
|
||||
*/
|
||||
public void load(Class<?> relativeClass, String... resourceNames) {
|
||||
Resource[] resources = new Resource[resourceNames.length];
|
||||
for (int i = 0; i < resourceNames.length; i++) {
|
||||
resources[i] = new ClassPathResource(resourceNames[i], relativeClass);
|
||||
}
|
||||
this.load(resources);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,13 +40,14 @@ import org.springframework.instrument.classloading.weblogic.WebLogicLoadTimeWeav
|
||||
* "<code>loadTimeWeaver</code>"; the most convenient way to achieve this is
|
||||
* Spring's <code><context:load-time-weaver></code> XML tag.
|
||||
*
|
||||
* <p>This class implements a runtime environment check for obtaining the
|
||||
* appropriate weaver implementation: As of Spring 2.5, it detects Sun's
|
||||
* GlassFish, Oracle's OC4J, BEA's WebLogic 10,
|
||||
* <p>This class implements a runtime environment check for obtaining
|
||||
* the appropriate weaver implementation: As of Spring 3.0, it detects
|
||||
* Oracle WebLogic 10, Oracle OC4J 10, GlassFish 3, JBoss AS 5 and 6,
|
||||
* {@link InstrumentationSavingAgent Spring's VM agent} and any
|
||||
* {@link ClassLoader} supported by Spring's {@link ReflectiveLoadTimeWeaver}
|
||||
* (for example the
|
||||
* {@link org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader}).
|
||||
* {@link org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader}
|
||||
* for Tomcat 5, 6 and 7).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Ramnivas Laddad
|
||||
|
||||
+20
-7
@@ -20,27 +20,40 @@ import java.util.Locale;
|
||||
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
import org.springframework.core.NamedInheritableThreadLocal;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
|
||||
/**
|
||||
* A holder for a thread-local user {@link JodaTimeContext}.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class JodaTimeContextHolder {
|
||||
|
||||
private static final ThreadLocal<JodaTimeContext> jodaTimeContextHolder =
|
||||
new NamedInheritableThreadLocal<JodaTimeContext>("JodaTime Context");
|
||||
new NamedThreadLocal<JodaTimeContext>("JodaTime Context");
|
||||
|
||||
|
||||
/**
|
||||
* Associate the given JodaTimeContext with the current thread.
|
||||
* @param context the current JodaTimeContext, or <code>null</code> to clear
|
||||
* the thread-bound context
|
||||
* Reset the JodaTimeContext for the current thread.
|
||||
*/
|
||||
public static void setJodaTimeContext(JodaTimeContext context) {
|
||||
jodaTimeContextHolder.set(context);
|
||||
public static void resetJodaTimeContext() {
|
||||
jodaTimeContextHolder.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the given JodaTimeContext with the current thread.
|
||||
* @param jodaTimeContext the current JodaTimeContext,
|
||||
* or <code>null</code> to reset the thread-bound context
|
||||
*/
|
||||
public static void setJodaTimeContext(JodaTimeContext jodaTimeContext) {
|
||||
if (jodaTimeContext == null) {
|
||||
resetJodaTimeContext();
|
||||
}
|
||||
else {
|
||||
jodaTimeContextHolder.set(jodaTimeContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user