Compare commits

..

194 Commits

Author SHA1 Message Date
Arjen Poutsma cda4ed26f1 Committed initial version of 3.0.2 tag 2010-04-02 10:36:59 +00:00
Juergen Hoeller 386b7507c6 final preparations for 3.0.2 2010-04-02 08:54:00 +00:00
Arjen Poutsma 8a1a23af83 SPR-7060 - @ResponseStatus: The reason value is not used. 2010-04-02 08:39:26 +00:00
Chris Beams 580dc8e72a typed map and collection conversion routines now eagerly reject non-assignable required types and avoid spurious InvocationException stack traces in debug log (SPR-7058) 2010-04-02 08:00:48 +00:00
Ramnivas Laddad 66d2c6698b Improved fix for SPR-6850 by dealing with bounds separately from normal types 2010-04-01 23:37:08 +00:00
Juergen Hoeller 7f90e3bcf7 enable JPATraversableResolver to introspect test domain classes 2010-04-01 11:45:01 +00:00
Juergen Hoeller bc1abe6070 prepared for 3.0.2 release 2010-04-01 11:38:14 +00:00
Juergen Hoeller 6aa0e62597 compatibility with Hibernate 3.5 final 2010-04-01 11:37:35 +00:00
Juergen Hoeller 52179d8bfb fixed TemplateParserContext documentation (SPR-7059) 2010-04-01 10:59:58 +00:00
Juergen Hoeller ee686188b7 OSGi version range accepts JasperReports 3.x as well; fixed missing Spring version placeholder in context-support bundle 2010-04-01 10:57:15 +00:00
Juergen Hoeller 4a98fcb3f7 fixed ambiguous reference to Entry type 2010-04-01 10:36:57 +00:00
Juergen Hoeller 29ab58c4d8 ResourcePatternUtils provides plain PathMatchingResourcePatternResolver in case of a null ResourceLoader 2010-04-01 10:35:49 +00:00
Juergen Hoeller f6d05eaad4 reintroduced two-arg constructor (making STS warning disappear); always use a ResourcePatternResolver (through ResourcePatternUtils) 2010-04-01 10:31:15 +00:00
Arjen Poutsma 5105793228 javadoc 2010-04-01 10:14:20 +00:00
Arjen Poutsma 689e7b7af2 Introduced ResponseEntity, for access to the response status code 2010-04-01 10:08:51 +00:00
Juergen Hoeller 636e2f0f4c final preparations for 3.0.2 2010-03-31 15:38:11 +00:00
Juergen Hoeller 461b488eee polishing 2010-03-31 15:36:35 +00:00
Juergen Hoeller 6b93f41f3a AbstractInterceptorDrivenBeanDefinitionDecorator preserves lazy-init flag as well 2010-03-31 15:25:35 +00:00
Juergen Hoeller 092241a632 fixed decorated BeanDefinition condition for early type checking in AbstractBeanFactory (SPR-7006) 2010-03-31 15:21:48 +00:00
Juergen Hoeller 20f4e9023b UrlPathHelper cuts off trailing servlet-path slashes for root mappings (on WebSphere; SPR-7052) 2010-03-31 14:02:27 +00:00
Juergen Hoeller c24bafd644 polishing 2010-03-31 13:38:15 +00:00
Juergen Hoeller 21b4526063 accept UrlMap with any value type 2010-03-31 13:37:46 +00:00
Juergen Hoeller b2ff0b1df0 refined internal HandlerMapping/HandlerAdapter bean names 2010-03-31 13:37:11 +00:00
Juergen Hoeller 87d0da2d4c final preparations for 3.0.2 2010-03-30 23:37:29 +00:00
Juergen Hoeller ad78b5cdb5 polishing 2010-03-30 23:35:13 +00:00
Juergen Hoeller de84703c02 @ExceptionHandler methods consistently receive original exception as thrown by user methods 2010-03-30 23:28:21 +00:00
Juergen Hoeller b67b5ec408 clarified applicability of @ExceptionHandler in Portlet environments (SPR-6959) 2010-03-30 21:27:40 +00:00
Juergen Hoeller 65e88449aa DispatcherPortlet passes handler instance into HandlerExceptionResolver for action exception; DispatcherPortlet applies preHandleRender callbacks in case of action exception as well (SPR-6959) 2010-03-30 21:17:31 +00:00
Juergen Hoeller 20de98362a use simple type name in "missing parameter" exception text 2010-03-30 21:13:12 +00:00
Juergen Hoeller ea7ff5241d polishing 2010-03-30 21:12:40 +00:00
Juergen Hoeller ae877e92c7 improved getBean(Class) javadoc 2010-03-30 15:53:32 +00:00
Juergen Hoeller 16305530f2 adapted to common naming convention for internal attributes 2010-03-30 15:44:11 +00:00
Juergen Hoeller 282de41f06 AbstractInterceptorDrivenBeanDefinitionDecorator exposes decorated BeanDefinition for early type checking in AbstractBeanFactory (SPR-7006) 2010-03-30 15:40:47 +00:00
Juergen Hoeller 16eb915c95 ObjectFactoryCreatingFactoryBean creates a serializable ObjectFactory reference; added ProviderCreatingFactoryBean, exposing a serializable JSR-330 Provider reference (SPR-6998) 2010-03-30 14:45:43 +00:00
Juergen Hoeller 0eabef0720 added filter ordering comments (SPR-6594) 2010-03-30 10:46:51 +00:00
Juergen Hoeller 2c9753ad25 NativeWebRequest detects native MultipartRequest even when decorated (SPR-6594) 2010-03-30 10:24:39 +00:00
Juergen Hoeller 81e81ce77c WebRequestInterceptor exposes HttpServletResponse through NativeWebRequest (after downcast) 2010-03-30 09:21:09 +00:00
Arjen Poutsma 9cecaa769e SPR-7047 - XML MarshallingView assumes non-null value for object to be marshalled. 2010-03-30 08:34:29 +00:00
Juergen Hoeller 8c8eca7e05 refined use of generics 2010-03-29 23:08:32 +00:00
Juergen Hoeller fba8bcc7dc compatibility with JasperReports 3.x in terms of resource management (SPR-7048) 2010-03-29 23:07:53 +00:00
Juergen Hoeller fa719ad4c5 restored compatibility with Servlet 2.4 containers on all VMs (SPR-7044) 2010-03-29 13:17:49 +00:00
Arjen Poutsma 63dc53a5ea SPR-6861 - enable overwriting of createHttpInputMessage and createHttpOutputMessage in AnnotationMethodHandlerAdapter 2010-03-29 12:25:49 +00:00
Arjen Poutsma bc7679f9fc Documented HttpEntity 2010-03-29 12:02:22 +00:00
Arjen Poutsma a6d5d7c8e2 javadoc 2010-03-29 11:21:55 +00:00
Arjen Poutsma 122e4346bb Documented HttpEntity 2010-03-29 11:12:45 +00:00
Arjen Poutsma c18137d40a SPR-6728 - Document Spring MVC exception -> HTTP status code mappings 2010-03-29 10:28:05 +00:00
Sam Brannen a827ab88b1 [SPR-6523] Commented all paragraphs (i.e., for list, map, and set) related to collection merging with the util namespace until this issue has been addressed. 2010-03-27 19:10:54 +00:00
Chris Beams 351e72b6e2 incorrectly invoked factory methods now result in exceptions with more descriptive messages (SPR-5475) 2010-03-26 12:05:36 +00:00
Juergen Hoeller cbed1c1b4b fixed collection element conversion using ConversionService (SPR-6950) 2010-03-25 15:02:19 +00:00
Arjen Poutsma 124837e2c3 Added @Override annotations. 2010-03-25 13:02:19 +00:00
Arjen Poutsma 753a54096f SPR-7000 - AnnotationMethodHandlerAdapter gives priority to media type order over quality when selecting a method 2010-03-25 12:29:52 +00:00
Juergen Hoeller d50881d82b fixed collection element conversion using ConversionService (SPR-6950) 2010-03-25 11:53:41 +00:00
Arjen Poutsma f836601e0f SPR-7034 - XmlBeans UnMarshalling - does not work with RequestBody annotation 2010-03-25 11:52:32 +00:00
Chris Beams fbda55f141 corrected TypeUtils.isAssignable() failure to return true in certain valid wildcard bounding scenarios (SPR-6850) 2010-03-25 10:33:25 +00:00
Juergen Hoeller 10c358718e avoid NPE if runtimeTest is null (SPR-7032) 2010-03-25 10:22:16 +00:00
Arjen Poutsma 6f2062fb3a SPR-7031 - MappingJacksonJsonView should add headers for no-caching 2010-03-25 10:14:11 +00:00
Juergen Hoeller f42d4241b4 preparations for 3.0.2 2010-03-25 00:00:27 +00:00
Juergen Hoeller 3576bc4585 preparations for 3.0.2 2010-03-24 23:53:02 +00:00
Thomas Risberg 47389a0edd added com.springsource.javax.servlet.jsp dependency to fix problem with test (SPR-7033) 2010-03-24 23:24:16 +00:00
Juergen Hoeller ab139dffd0 added javadoc references to semantic definition of transaction attributes (SPR-7029) 2010-03-24 23:22:52 +00:00
Thomas Risberg a5f3d00977 added conf attribute for the struts dependency (SPR-7033) 2010-03-24 22:39:47 +00:00
Juergen Hoeller 53b6e1c1b0 fixed DataBinder's conversion error handling for direct field access with ConversionService (SPR-6953) 2010-03-24 17:40:45 +00:00
Juergen Hoeller 65b0a8fcb2 revised BeanTypeDescriptor into core PropertyTypeDescriptor; consider method annotations for return type (SPR-6979) 2010-03-24 16:27:33 +00:00
Juergen Hoeller 461c200ce6 restricted onApplicationEvent callbacks for local ApplicationContext only (SPR-6964) 2010-03-24 14:38:10 +00:00
Juergen Hoeller a614430899 allow for null keys and null values in rendered Map (SPR-7024) 2010-03-24 14:26:00 +00:00
Juergen Hoeller bc2440ea16 updated for JDK 1.5+ 2010-03-24 13:58:45 +00:00
Juergen Hoeller 6fb49f1de7 ignore failing serialization test for the time being 2010-03-24 10:52:20 +00:00
Chris Beams 6118d67321 updated JavaDoc regarding short-circuiting the BeanPostProcessor chain when returning null from BPP methods (SPR-6926) 2010-03-24 10:52:10 +00:00
Juergen Hoeller cbca6e1acb prevent findEditorByConvention AccessControlException on Google App Engine (SEC-1434) 2010-03-24 10:39:40 +00:00
Juergen Hoeller 2c2cf32b8a polishing 2010-03-24 10:35:50 +00:00
Juergen Hoeller 89755542da BeanPostProcessors are allowed to return a null bean value in the middle of the chain (SPR-6926) 2010-03-24 10:34:21 +00:00
Chris Beams 051b5f4f4f removed duplicate junit and aspectjweaver dependencies 2010-03-24 10:09:58 +00:00
Juergen Hoeller b370969690 added public "validateDatabaseSchema" method to Hibernate LocalSessionFactoryBean (SPR-3212) 2010-03-24 09:36:01 +00:00
Chris Beams a1f6eabbce SPR-7002: updated .classpath and pom to reflect new dependency upgrade from Jackson 1.0.0->1.4.2 2010-03-24 09:27:54 +00:00
Chris Beams 247c46e6ea SPR-7002: updated .classpath and pom to reflect new dependency upgrade from Jackson 1.0.0->1.4.2 2010-03-24 09:03:39 +00:00
Juergen Hoeller 915ca47cad updated to Jackson 1.4.2 2010-03-24 09:01:55 +00:00
Mark Fisher 0d8a020684 updated commons-pool version in .classpath to match ivy config 2010-03-23 21:44:52 +00:00
Mark Pollack 1e388a894e Change version of Hibernate Validator to 4.0.2 in pom.xml and eclipse .classpath to agree with version in ivy.xml 2010-03-23 16:44:46 +00:00
Juergen Hoeller 4e7752c9ba JCA listener containers delegate to wrapped Transaction handle (for Geronimo compatibility; SPR-6991) 2010-03-23 16:27:34 +00:00
Chris Beams c13e5f9f5b SPR-7009, SPR-6972: backed out unintentionally committed tests 2010-03-23 15:29:35 +00:00
Chris Beams 706a09c49e SPR-7009: TransactionInterceptor now extracts ultimate target class before evaluating @Transactional metadata to accommodate double-proxying cases 2010-03-23 12:06:30 +00:00
Chris Beams c38c09bc35 SPR-6972: removed import 2010-03-23 12:06:24 +00:00
Chris Beams 77bb68b967 SPR-6972: failed attempt to reproduce issue 2010-03-23 12:06:16 +00:00
Arjen Poutsma 212daa1995 SPR-7002 - RestTemplate fails to convert properly for Generic Type Container with MappingJacksonHttpMessageConverter 2010-03-23 11:15:13 +00:00
Arjen Poutsma f7ac7a395c SPR-6021 - Allow for using MultiValueMap in GET request for mapping multiple request params 2010-03-23 09:50:47 +00:00
Arjen Poutsma 465e84eda4 Revert: SPR-6021 - Allow for using MultiValueMap in GET request for mapping multiple request params 2010-03-23 08:52:59 +00:00
Chris Beams ec577f8e24 SPR-6538: context-support is no longer marked as an optional dependency within aspects and webmvc POMs 2010-03-23 08:15:57 +00:00
Juergen Hoeller 26470cc23a polishing 2010-03-22 18:31:41 +00:00
Juergen Hoeller 296aa96d71 AopUtils.getTargetClass(...) never returns null (SPR-7011) 2010-03-22 18:31:13 +00:00
Juergen Hoeller a2c3274b8e fixed double fixedField call for getFieldType (SPR-7019) 2010-03-22 15:08:57 +00:00
Chris Beams 5e19f2959e SPR-6888: ClassPathResource.getDescription() now fully qualifies resource path regardless of constructor used. 2010-03-22 14:54:39 +00:00
Juergen Hoeller 5dc59aaa7b avoid Synchronization List preparations upfront if possible (SPR-6999) 2010-03-22 14:31:58 +00:00
Arjen Poutsma c9289a4dcf SPR-6021 - Allow for using MultiValueMap in GET request for mapping multiple request params 2010-03-22 14:31:27 +00:00
Juergen Hoeller 19b4618fb5 avoid Synchronization List preparations upfront if possible (SPR-6999) 2010-03-22 14:23:02 +00:00
Arjen Poutsma 4c0744ee54 SPR-6978 - Dispatcher fails to invoke handler method when request method conflicts with request path 2010-03-22 14:12:32 +00:00
Arjen Poutsma b07d02f1bf SPR-7018 - Support for HttpEntity<?> in @MVC 2010-03-22 10:23:39 +00:00
Sam Brannen 69cbadf7e9 [SPR-6918] Now verifying support for @Value in conjunction with the Spring TestContext Framework. 2010-03-19 12:57:17 +00:00
Sam Brannen 0543036ec9 FooConfig, Foo, Bar, and BarFactory are now public static classes in order to avoid a bug with JDT/Spring IDE where the classes cannot be found in the XML application context. 2010-03-19 12:39:34 +00:00
Thomas Risberg 2ff2f0205d added metadata override to NUMERIC for NUMBER columns reported as DECIMAL but with zero decimal places (SPR-6912) 2010-03-18 14:19:30 +00:00
Christian Dupuis e22431188b made SortedResourcesFactoryBean ResourceLoaderAware to prevent specifying the ResourceLoader in the jdbc NamespaceHandlers; prevents leaking of class loader instances in tooling 2010-03-17 17:35:27 +00:00
Juergen Hoeller b8c0e153e3 do not insist on BeanDefinition presence for @Value resolution (for use in unit tests; SPR-6918) 2010-03-16 23:47:40 +00:00
Juergen Hoeller ff09482653 avoid ChainedTilesRequestContextFactory warn logging on Tiles 2.2 2010-03-16 23:27:18 +00:00
Andy Clement d932c043da SPR-6984: auto grow collections on write through indexer 2010-03-15 18:15:48 +00:00
Juergen Hoeller 0cb7e4dcb3 made getName() public; added isNullSafe() accessor (SPR-6980) 2010-03-14 22:19:56 +00:00
Christian Dupuis 2e5f1c22f6 fixed Eclipse classpath file 2010-03-14 17:58:46 +00:00
Chris Beams cf93e7c69e Fixed typo in javadoc on HttpRequestHandler 2010-03-14 11:26:06 +00:00
Juergen Hoeller 9da980d325 further fixes for 3.0.2 2010-03-12 23:12:40 +00:00
Juergen Hoeller 7da13e7ad1 compatibility with OpenJPA 2.0 (support for persistence.xml versioning; SPR-6975) 2010-03-12 23:10:06 +00:00
Juergen Hoeller a0e40a5610 avoid ChainedTilesRequestContextFactory warn logging on Tiles 2.1 2010-03-12 22:36:24 +00:00
Juergen Hoeller ac5c75690a fixed test failures 2010-03-12 20:55:44 +00:00
Juergen Hoeller 795a5e02cd polishing 2010-03-12 20:45:02 +00:00
Juergen Hoeller bb75662a7e @Transactional qualifiers work in unit tests as well (SPR-6892) 2010-03-12 20:44:41 +00:00
Juergen Hoeller 23cb161fb3 polishing 2010-03-12 19:45:17 +00:00
Juergen Hoeller eb1c039a6e WebContentInterceptor does not restrict HTTP methods by default anymore (SPR-6919) 2010-03-12 19:45:05 +00:00
Juergen Hoeller 4c39f90466 made CronSequenceGenerator public (SPR-6920) 2010-03-12 19:34:45 +00:00
Juergen Hoeller d4de1ac346 AbstractInterceptorDrivenBeanDefinitionDecorator copies autowire settings just like ScopedProxyUtils does (SPR-6974) 2010-03-12 19:18:39 +00:00
Arjen Poutsma 4880d1d461 SPR-6976 - Add debug log for HttpMessageConverter usage 2010-03-12 17:46:50 +00:00
Arjen Poutsma 5a8aa53232 SPR-6973 - SimpleUrlHandlerMapping wildcards cannot handle escaped newline characters 2010-03-12 16:56:16 +00:00
Arjen Poutsma 85b8befbd1 SPR-6970 - AbstractHttpMessageConverter canWrite logic the wrong way round?? 2010-03-12 16:43:57 +00:00
Christian Dupuis 4c4f19ec94 SPR-6977: updated copyright; added method comment 2010-03-12 16:10:03 +00:00
Christian Dupuis 145dcfd0c2 SPR-6977: added support for array parameter types 2010-03-12 15:09:24 +00:00
Arjen Poutsma 991c982e5b SPR-5866 - RestTemplate - access to Request Headers 2010-03-12 09:07:29 +00:00
Juergen Hoeller 1d6f374970 fixed typo (SPR-6967) 2010-03-11 21:30:39 +00:00
Juergen Hoeller eee72c52da mention actual endpoint address in connect failure exception message (SPR-6971) 2010-03-11 21:26:10 +00:00
Arjen Poutsma b0e3081636 SPR-5866 - RestTemplate - access to Request Headers 2010-03-11 17:41:30 +00:00
Arjen Poutsma 886eb665bf SPR-5866 - RestTemplate - access to Request Headers 2010-03-11 17:35:08 +00:00
Arjen Poutsma 70ee2ee7b1 SPR-5866 - RestTemplate - access to Request Headers 2010-03-11 17:33:54 +00:00
Arjen Poutsma f3f535623f Fixing the build 2010-03-11 16:54:47 +00:00
Arjen Poutsma 63076d0865 SPR-6969 - Introduce HttpEntity 2010-03-11 16:42:25 +00:00
Arjen Poutsma fc0a6ce40c Javadoc 2010-03-11 14:19:30 +00:00
Arjen Poutsma 88773ae7f1 a HTTP -> an HTTP 2010-03-11 12:57:52 +00:00
Andy Clement 81b10be1d0 SPR-6968: indexing via square brackets can now treat the index as an attempt at property access 2010-03-11 01:09:50 +00:00
Scott Andrews 50c5593740 SPR-6923 SpEL resolving nested property as outer object 2010-03-10 17:44:14 +00:00
Arjen Poutsma af4b22e5b9 SPR-5904 - Merged multipart support into FormHttpMessageConverter 2010-03-10 17:31:02 +00:00
Arjen Poutsma 6e55c8cd2f Fixing build. 2010-03-10 14:03:56 +00:00
Arjen Poutsma def90d1016 SPR-5904 - Multipart/mixed requests using RestTemplate 2010-03-10 13:53:29 +00:00
Juergen Hoeller f30b0a86f7 autowire="byType" ignores parameter name when choosing a primary bean, as defined (SPR-6917) 2010-03-10 13:46:31 +00:00
Juergen Hoeller 95ad7168bf changed doGetBean signature back to protected (SPR-6957) 2010-03-10 13:38:46 +00:00
Juergen Hoeller ccb312a974 SimpleJdbcCall's "returningResultSet" accepts any plain RowMapper now (SPR-6963) 2010-03-10 12:54:52 +00:00
Arjen Poutsma f588ab05fa Added readonly version of HttpHeaders 2010-03-10 10:00:03 +00:00
Andy Clement 2dd1134303 SPR-6941: part (1) correct exception handling when null cachedExecutor 2010-03-09 17:33:36 +00:00
Arjen Poutsma 0efb9d8023 SPR-5904 - Multipart/mixed requests using RestTemplate 2010-03-09 16:15:41 +00:00
Arjen Poutsma 21fd150894 SPR-6906 - Combination of ControllerClassNameHandlerMapping and @RequestMappings with file extensions results in exception 2010-03-09 10:29:01 +00:00
Arjen Poutsma ac9a625ccc SPR-6939 - XStreamMarshaller + JsonHierarchicalStreamDriver + JsonWriter.DROP_ROOT_MODE produce empty output 2010-03-09 09:53:51 +00:00
Andy Clement c31213e5cb SPR-6866: unhelpful NPE when expression badly formed 2010-03-09 00:55:03 +00:00
Ramnivas Laddad f82cc6458b Fixed SPR-6734 by resticting record/replay logic to only entity methods that originated in a test method 2010-03-08 20:42:22 +00:00
David Syer 8d7df01d73 RESOLVED - issue SPR-6955, SPR-6901 added DisposableBean to TaskExecutorFactoryBean 2010-03-08 12:13:30 +00:00
Arjen Poutsma 5303ab68aa Atom Feed HttpMessageConverter 2010-03-05 14:32:36 +00:00
Arjen Poutsma c91ff130d5 SPR-6946 - RestTemplate should not encode fragments (#'s) 2010-03-05 11:40:52 +00:00
Juergen Hoeller 54d0346084 do not call isCurrentlyInCreation with null argument (in order to meet newly enforced assertions within the BeanFactory) 2010-03-05 10:49:24 +00:00
Juergen Hoeller 4f926c82bf added bean name assertions 2010-03-04 22:36:35 +00:00
Juergen Hoeller b07b146965 fixed @Configurable issue with null bean name (SPR-6947) 2010-03-04 22:33:59 +00:00
Juergen Hoeller cfbc5224e3 fixed exception propagation issue with Hessian 4.0 (SPR-6899) 2010-03-04 22:22:47 +00:00
Arjen Poutsma a0c41a0e03 SPR-6906 - Combination of ControllerClassNameHandlerMapping and @RequestMappings with file extensions results in exception 2010-03-04 15:17:09 +00:00
Juergen Hoeller 8fe5151f84 some further 3.0.2 entries 2010-03-04 13:58:23 +00:00
Juergen Hoeller 77f8b070cd polishing 2010-03-04 13:58:02 +00:00
Arjen Poutsma 4f4f3fab7d SPR-6934 - AnnotationMethodHandlerAdapter should take into account request accept header ordering 2010-03-04 13:54:24 +00:00
Juergen Hoeller 0444ab236a fixed TypeDescriptor toString for MethodParameter annotations (SPR-6924) 2010-03-04 13:50:43 +00:00
Juergen Hoeller 9ede9fe697 "conversionService" bean gets ignored if not of type ConversionService (SPR-6916) 2010-03-04 11:27:09 +00:00
Juergen Hoeller 3e98b26b77 fixed typo (SPR-6936) 2010-03-04 11:17:12 +00:00
Juergen Hoeller 0aee6e9f5b use target factory's ClassLoader in case of a raw EntityManagerFactory (SPR-6733) 2010-03-04 11:13:28 +00:00
Arjen Poutsma eddc5b8898 SPR-6935 - @ResponseBody with method that return void throws "Could not resolve view exception". 2010-03-04 10:51:27 +00:00
Juergen Hoeller 57993d871e WebApplicationObjectSupport's initServletContext will be called only once in any scenario (SPR-6914) 2010-03-03 16:26:47 +00:00
Arjen Poutsma 3c8a47bd06 SPR-6877 - AnnotationMethodHandlerAdapter.handleResponseBody prioritizes messageConverter over MediaType 2010-03-03 11:14:30 +00:00
Arjen Poutsma 7f8c91a52d SPR-6902 - @ResponseBody does not work with @ExceptionHandler 2010-03-03 10:33:58 +00:00
Arjen Poutsma 62f9f477f5 SPR-6877 - AnnotationMethodHandlerAdapter.handleResponseBody prioritizes messageConverter over MediaType 2010-03-03 10:18:59 +00:00
Arjen Poutsma 894875ce8d SPR-6907 - JibxMarshaller - provide access to jibx's writeDocType 2010-03-02 12:49:31 +00:00
Arjen Poutsma 9d1c3fa9ac SPR-6907 - JibxMarshaller - provide access to jibx's writeDocType 2010-03-02 11:56:22 +00:00
Arjen Poutsma d207c2294d Fixed wrong encoding of URI templates with @-signs (SPR-6874) 2010-03-02 11:30:36 +00:00
Arjen Poutsma e653a9cd03 javadoc 2010-03-02 10:53:15 +00:00
Arjen Poutsma 5675046cb7 SPR-6876 - RequestMethod does not appear to factor into @RequestMapping uniqueness in some cases 2010-03-02 09:52:43 +00:00
Costin Leau 20a8039642 + improve template for spring-context so that the import-package is updated automatically 2010-02-25 15:46:54 +00:00
Juergen Hoeller 4bda92fd8a newArg(Type)PreparedStatementSetter declares PreparedStatementSetter interface as return type (SPR-6897) 2010-02-24 14:32:22 +00:00
Sam Brannen 97adfdd398 Removed misleading comments regarding javax.inject.Qualifier. 2010-02-23 23:07:44 +00:00
Sam Brannen a5b5df450e [SPR-6879] @DirtiesContext is now an @Inherited annotation. 2010-02-23 17:44:59 +00:00
Sam Brannen 80b8fb8b83 [SPR-6879] @DirtiesContext is now an @Inherited annotation. 2010-02-23 17:43:00 +00:00
Juergen Hoeller ef227c5d01 HibernateJpaDialect borrows JDBC Connection on demand (supporting aggressive release; SPR-6895) 2010-02-23 16:13:04 +00:00
Michael Isvy 9e5b129ba5 SPR-6885
updates based on Chris Beams' comments.
2010-02-23 15:46:52 +00:00
Juergen Hoeller 12b30843c5 widened AbstractFactoryBean's "getObjectType" signature to return any Class as well (SPR-6872) 2010-02-23 13:00:12 +00:00
Juergen Hoeller 09f02bc620 use WeakHashMap for DataSource-keyed cache (SPR-6887) 2010-02-23 10:47:51 +00:00
Chris Beams 3d2611484a adding .gitignore 2010-02-22 23:52:56 +00:00
Michael Isvy 6af91773ee SPR-6885
Improved documentation for JavaConfig's use of CGLIB for all @Configuration annotated classes
2010-02-22 13:50:41 +00:00
Juergen Hoeller 9e71af86f8 polishing 2010-02-22 11:49:19 +00:00
Juergen Hoeller 60ff93e5ac avoid invalid id characters in ErrorsTag as well (SPR-6862) 2010-02-22 11:48:08 +00:00
Chris Beams f25d2a9416 Removed hard-coded local path from .core/.classpath; removed duplicate asm entry in .context/.classpath 2010-02-22 01:55:38 +00:00
David Syer fd4b9cf6a3 SPR-6881: remove extra dependency 2010-02-21 17:51:48 +00:00
David Syer 1a351db6e0 Update Central POMs to 3.0.2 2010-02-21 15:32:18 +00:00
Chris Beams 5b537e9604 minor typo fixes 2010-02-21 02:13:41 +00:00
Juergen Hoeller 6c69f47acf regressions 2010-02-20 16:29:07 +00:00
Juergen Hoeller 44ef114981 fixed @RequestParam(required=false) regression for @InitBinder methods (SPR-6878) 2010-02-20 16:14:14 +00:00
Juergen Hoeller 67b342d923 fixed indexed property regression (SPR-6871) 2010-02-20 15:53:09 +00:00
Juergen Hoeller 5063c6dd00 upgraded to Hibernate Validator 4.0.2 and Jackson 1.4.2 2010-02-19 13:58:19 +00:00
Costin Leau 8d0bb00188 + make use or property placeholders inside template.mf 2010-02-19 09:43:22 +00:00
Arjen Poutsma fe59d4a787 setting things up for 3.0.2 2010-02-18 17:42:14 +00:00
297 changed files with 8520 additions and 2597 deletions
+5
View File
@@ -0,0 +1,5 @@
target
integration-repo
ivy-cache
spring-build
jmx.log
+44 -1
View File
@@ -3,6 +3,49 @@ SPRING FRAMEWORK CHANGELOG
http://www.springsource.org
Changes in version 3.0.2 (2010-04-02)
-------------------------------------
* fixed cross-module version ranges in OSGi manifests
* fixed contents of org.springframework.web.struts jar
* upgraded to Hibernate Validator 4.0.2 and Jackson 1.4.2
* compatibility with Hibernate 3.5 final (native and also as a JPA 2.0 provider)
* compatibility with OpenJPA 2.0 (support for JPA 2.0 persistence.xml versioning)
* compatibility with Hessian 4.0 (in terms of exception propagation)
* compatibility with JasperReports 3.x (in terms of resource management)
* restored full compatibility with Servlet 2.4 containers on all VMs
* PropertyEditor lookup fallback works on Google App Engine as well
* fixed TypeDescriptor/MethodParameter toString for all cases in debug log messages
* widened AbstractFactoryBean's "getObjectType" signature to return any Class as well
* BeanPostProcessors are allowed to return a null bean value in the middle of the chain
* autowire="byType" ignores parameter name when choosing a primary bean, as defined
* ObjectFactoryCreatingFactoryBean creates a serializable ObjectFactory reference
* added ProviderCreatingFactoryBean, exposing a serializable JSR-330 Provider reference
* "conversionService" bean will be ignored if it is not of type ConversionService
* revised AbstractInterceptorDrivenBeanDefinitionDecorator for alignment with auto-proxying
* SimpleJdbcCall's "returningResultSet" accepts any plain RowMapper now
* added public "validateDatabaseSchema" method to Hibernate LocalSessionFactoryBean
* HibernateJpaDialect borrows JDBC Connection on demand (supporting aggressive release)
* JCA listener containers delegate to wrapped Transaction handle (for Geronimo compatibility)
* @Transactional qualifiers work in unit tests as well (TransactionalTestExecutionListener)
* @Value processing works in test instances (using the test context framework) as well now
* @DirtiesContext is now inherited for class-level usage
* NativeWebRequest detects native MultipartRequest when decorated by HiddenHttpMethodFilter
* WebRequestInterceptor exposes HttpServletResponse through NativeWebRequest (after downcast)
* WebContentInterceptor does not restrict HTTP methods by default anymore
* WebApplicationObjectSupport's initServletContext will be called only once in any scenario
* DispatcherPortlet passes handler instance into HandlerExceptionResolver for action exception
* DispatcherPortlet applies preHandleRender callbacks in case of action exception as well
* UrlPathHelper cuts off trailing servlet-path slashes for root mappings (on WebSphere)
* introduced support for HttpEntity and ResponseEntity wrappers, adding context to body values
* fixed DataBinder's conversion error handling for direct field access with ConversionService
* @InitBinder methods support all applicable Spring 3.0 parameter annotations as well
* fixed @RequestParam(required=false) regression for @InitBinder methods
* @ExceptionHandler methods consistently receive original exception
* fixed indexed property binding regression in form tag library
* fixed @Configurable issue with null bean name
Changes in version 3.0.1 (2010-02-18)
-------------------------------------
@@ -12,7 +55,7 @@ Changes in version 3.0.1 (2010-02-18)
* support for Hibernate 3.5 (as native Hibernate API and as JPA 2.0 provider)
* support for Tiles 2.2.1 (preserving compatibility with Tiles 2.1.2 and above)
* consistent treatment of unresolvable placeholders for Resource and Resource array properties
* ConversionFailedException exposes offending value through public "getValue()" method
* ConversionFailedException exDLBFposes offending value through public "getValue()" method
* fixed BeanFactory's "getBeansWithAnnotation" to ignore beans with non-determinable type
* widened FactoryBean's "getObjectType" signature to return any Class (Class<?>)
* do not ever consider Object as a candidate type for autowiring by type (autowire="byType")
+2 -2
View File
@@ -1,5 +1,5 @@
SPRING FRAMEWORK 3.0.1 (February 2010)
------------------------------------
SPRING FRAMEWORK 3.0.2 (April 2010)
-----------------------------------
http://www.springframework.org
1. INTRODUCTION
+7 -1
View File
@@ -1,4 +1,10 @@
version=3.0.1
version=3.0.2
# 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=release
build.stamp=RELEASE
natural.name=spring-framework
+21 -20
View File
@@ -1,21 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-1.0.0.jar" sourcepath="/IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-2.5.1.jar" sourcepath="/IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-sources-2.5.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/com.jamonapi/com.springsource.com.jamonapi/2.4.0/com.springsource.com.jamonapi-2.4.0.jar" sourcepath="/IVY_CACHE/com.jamonapi/com.springsource.com.jamonapi/2.4.0/com.springsource.com.jamonapi-sources-2.4.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.2.0/com.springsource.net.sf.cglib-2.2.0.jar" sourcepath="/IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.1.3/com.springsource.net.sf.cglib-sources-2.1.3.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-1.2.15.jar" sourcepath="/IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-sources-1.2.15.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.7.0/com.springsource.org.junit-4.7.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.7.0/com.springsource.org.junit-sources-4.7.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.3.0/com.springsource.org.apache.commons.pool-1.3.0.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.3.0/com.springsource.org.apache.commons.pool-sources-1.3.0.jar"/>
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-1.0.0.jar" sourcepath="/IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-2.5.1.jar" sourcepath="/IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-sources-2.5.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/com.jamonapi/com.springsource.com.jamonapi/2.4.0/com.springsource.com.jamonapi-2.4.0.jar" sourcepath="/IVY_CACHE/com.jamonapi/com.springsource.com.jamonapi/2.4.0/com.springsource.com.jamonapi-sources-2.4.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.2.0/com.springsource.net.sf.cglib-2.2.0.jar" sourcepath="/IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.1.3/com.springsource.net.sf.cglib-sources-2.1.3.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-1.2.15.jar" sourcepath="/IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-sources-1.2.15.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.7.0/com.springsource.org.junit-4.7.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.7.0/com.springsource.org.junit-sources-4.7.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.3.0/com.springsource.org.apache.commons.pool-1.3.0.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.3.0/com.springsource.org.apache.commons.pool-sources-1.3.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar" sourcepath="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-sources-1.6.8.RELEASE.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.beans"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.core"/>
<classpathentry kind="lib" path="/org.springframework.asm/target/artifacts/org.springframework.asm.jar" sourcepath="/org.springframework.asm/target/artifacts/org.springframework.asm-sources.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.beans"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.core"/>
<classpathentry kind="lib" path="/org.springframework.asm/target/artifacts/org.springframework.asm.jar" sourcepath="/org.springframework.asm/target/artifacts/org.springframework.asm-sources.jar"/>
<classpathentry kind="var" path="IVY_CACHE"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
+2 -2
View File
@@ -4,12 +4,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<packaging>jar</packaging>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
</parent>
<dependencies>
@@ -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.
@@ -18,6 +18,7 @@ package org.springframework.aop.aspectj;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
@@ -139,9 +140,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
private boolean argumentsIntrospected = false;
// The actual type is java.lang.reflect.Type,
// but for JDK 1.4 compatibility we use Object as the static type.
private Object discoveredReturningGenericType;
private Type discoveredReturningGenericType;
// Note: Unlike return type, no such generic information is needed for the throwing type,
// since Java doesn't allow exception types to be parameterized.
@@ -295,7 +294,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
return this.discoveredReturningType;
}
protected Object getDiscoveredReturningGenericType() {
protected Type getDiscoveredReturningGenericType() {
return this.discoveredReturningGenericType;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 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.
@@ -69,21 +69,11 @@ public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice implement
*/
private boolean shouldInvokeOnReturnValueOf(Method method, Object returnValue) {
Class type = getDiscoveredReturningType();
Object genericType = getDiscoveredReturningGenericType();
Type genericType = getDiscoveredReturningGenericType();
// If we aren't dealing with a raw type, check if generic parameters are assignable.
return (ClassUtils.isAssignableValue(type, returnValue) &&
(genericType == null || genericType == type || GenericTypeMatcher.isAssignable(genericType, method)));
}
/**
* Inner class to avoid a static JDK 1.5 dependency for generic type matching.
*/
private static class GenericTypeMatcher {
public static boolean isAssignable(Object genericType, Method method) {
return TypeUtils.isAssignable((Type) genericType, method.getGenericReturnType());
}
(genericType == null || genericType == type ||
TypeUtils.isAssignable(genericType, method.getGenericReturnType())));
}
}
@@ -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.
@@ -73,7 +73,7 @@ class RuntimeTestWalker {
catch (IllegalAccessException illegalAccessEx) {
// Famous last words... but I don't see how this can happen given the
// makeAccessible call above
throw new IllegalStateException("Unable to access ShadowMatchImpl.runtimeTest field.");
throw new IllegalStateException("Unable to access ShadowMatchImpl.residualTest field");
}
}
@@ -83,15 +83,18 @@ class RuntimeTestWalker {
* then it tests subtype sensitive vars.
*/
public boolean testsSubtypeSensitiveVars() {
return new SubtypeSensitiveVarTypeTestVisitor().testsSubtypeSensitiveVars(this.runtimeTest);
return (this.runtimeTest != null &&
new SubtypeSensitiveVarTypeTestVisitor().testsSubtypeSensitiveVars(this.runtimeTest));
}
public boolean testThisInstanceOfResidue(Class thisClass) {
return new ThisInstanceOfResidueTestVisitor(thisClass).thisInstanceOfMatches(this.runtimeTest);
return (this.runtimeTest != null &&
new ThisInstanceOfResidueTestVisitor(thisClass).thisInstanceOfMatches(this.runtimeTest));
}
public boolean testTargetInstanceOfResidue(Class targetClass) {
return new TargetInstanceOfResidueTestVisitor(targetClass).targetInstanceOfMatches(this.runtimeTest);
return (this.runtimeTest != null &&
new TargetInstanceOfResidueTestVisitor(targetClass).targetInstanceOfMatches(this.runtimeTest));
}
@@ -139,8 +142,7 @@ class RuntimeTestWalker {
try {
Field varTypeField = ReflectionVar.class.getDeclaredField("varType");
ReflectionUtils.makeAccessible(varTypeField);
Integer varTypeValue = (Integer) varTypeField.get(v);
return varTypeValue.intValue();
return (Integer) varTypeField.get(v);
}
catch (NoSuchFieldException noSuchFieldEx) {
throw new IllegalStateException("the version of aspectjtools.jar / aspectjweaver.jar " +
@@ -150,7 +152,7 @@ class RuntimeTestWalker {
catch (IllegalAccessException illegalAccessEx) {
// Famous last words... but I don't see how this can happen given the
// makeAccessible call above
throw new IllegalStateException("Unable to access ReflectionVar.varType field.");
throw new IllegalStateException("Unable to access ReflectionVar.varType field");
}
}
}
@@ -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.
@@ -58,18 +58,13 @@ class InstantiationModelAwarePointcutAdvisorImpl
private String aspectName;
private Boolean isBeforeAdvice = null;
private Boolean isBeforeAdvice;
private Boolean isAfterAdvice = null;
private Boolean isAfterAdvice;
public InstantiationModelAwarePointcutAdvisorImpl(
AspectJAdvisorFactory af,
AspectJExpressionPointcut ajexp,
MetadataAwareAspectInstanceFactory aif,
Method method,
int declarationOrderInAspect,
String aspectName) {
public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp,
MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) {
this.declaredPointcut = ajexp;
this.method = method;
@@ -21,9 +21,9 @@ import java.util.List;
import org.w3c.dom.Node;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedList;
@@ -63,33 +63,38 @@ public abstract class AbstractInterceptorDrivenBeanDefinitionDecorator implement
// get the root bean name - will be the name of the generated proxy factory bean
String existingBeanName = definitionHolder.getBeanName();
BeanDefinition existingDefinition = definitionHolder.getBeanDefinition();
BeanDefinition targetDefinition = definitionHolder.getBeanDefinition();
BeanDefinitionHolder targetHolder = new BeanDefinitionHolder(targetDefinition, existingBeanName + ".TARGET");
// delegate to subclass for interceptor definition
BeanDefinition interceptorDefinition = createInterceptorDefinition(node);
// generate name and register the interceptor
String interceptorName = existingBeanName + "." + getInterceptorNameSuffix(interceptorDefinition);
BeanDefinitionReaderUtils.registerBeanDefinition(new BeanDefinitionHolder(interceptorDefinition, interceptorName), registry);
BeanDefinitionReaderUtils.registerBeanDefinition(
new BeanDefinitionHolder(interceptorDefinition, interceptorName), registry);
BeanDefinitionHolder result = definitionHolder;
if (!isProxyFactoryBeanDefinition(existingDefinition)) {
if (!isProxyFactoryBeanDefinition(targetDefinition)) {
// create the proxy definition
RootBeanDefinition proxyDefinition = new RootBeanDefinition();
// create proxy factory bean definition
proxyDefinition.setBeanClass(ProxyFactoryBean.class);
// set up property values
MutablePropertyValues mpvs = new MutablePropertyValues();
proxyDefinition.setPropertyValues(mpvs);
proxyDefinition.setScope(targetDefinition.getScope());
proxyDefinition.setLazyInit(targetDefinition.isLazyInit());
// set the target
mpvs.add("target", existingDefinition);
proxyDefinition.setDecoratedDefinition(targetHolder);
proxyDefinition.getPropertyValues().add("target", targetHolder);
// create the interceptor names list
mpvs.add("interceptorNames", new ManagedList<String>());
proxyDefinition.getPropertyValues().add("interceptorNames", new ManagedList<String>());
// copy autowire settings from original bean definition.
proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
proxyDefinition.setPrimary(targetDefinition.isPrimary());
if (targetDefinition instanceof AbstractBeanDefinition) {
proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
}
// wrap it in a BeanDefinitionHolder with bean name
result = new BeanDefinitionHolder(proxyDefinition, existingBeanName);
}
@@ -99,7 +104,8 @@ public abstract class AbstractInterceptorDrivenBeanDefinitionDecorator implement
@SuppressWarnings("unchecked")
private void addInterceptorNameToList(String interceptorName, BeanDefinition beanDefinition) {
List<String> list = (List<String>) beanDefinition.getPropertyValues().getPropertyValue("interceptorNames").getValue();
List<String> list = (List<String>)
beanDefinition.getPropertyValues().getPropertyValue("interceptorNames").getValue();
list.add(interceptorName);
}
@@ -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.
@@ -146,7 +146,7 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
* unless a hook method throws an exception.
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation = null;
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
@@ -169,7 +169,7 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal = null;
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
@@ -239,7 +239,7 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
return false;
}
JdkDynamicAopProxy otherProxy = null;
JdkDynamicAopProxy otherProxy;
if (other instanceof JdkDynamicAopProxy) {
otherProxy = (JdkDynamicAopProxy) other;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 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.
@@ -52,7 +52,7 @@ public abstract class AutoProxyUtils {
* @return whether the given bean should be proxied with its target class
*/
public static boolean shouldProxyTargetClass(ConfigurableListableBeanFactory beanFactory, String beanName) {
if (beanFactory.containsBeanDefinition(beanName)) {
if (beanName != null && beanFactory.containsBeanDefinition(beanName)) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
return Boolean.TRUE.equals(bd.getAttribute(PRESERVE_TARGET_CLASS_ATTRIBUTE));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 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.
@@ -45,7 +45,7 @@ public abstract class ExposeBeanNameAdvisors {
* Binding for the bean name of the bean which is currently being invoked
* in the ReflectiveMethodInvocation userAttributes Map.
*/
private static final String BEAN_NAME_ATTRIBUTE = ExposeBeanNameAdvisors.class.getName() + ".beanName";
private static final String BEAN_NAME_ATTRIBUTE = ExposeBeanNameAdvisors.class.getName() + ".BEAN_NAME";
/**
@@ -114,7 +114,7 @@ public abstract class ExposeBeanNameAdvisors {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
pmi.setUserAttribute(BEAN_NAME_ATTRIBUTE, beanName);
pmi.setUserAttribute(BEAN_NAME_ATTRIBUTE, this.beanName);
return mi.proceed();
}
}
@@ -137,7 +137,7 @@ public abstract class ExposeBeanNameAdvisors {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
pmi.setUserAttribute(BEAN_NAME_ATTRIBUTE, beanName);
pmi.setUserAttribute(BEAN_NAME_ATTRIBUTE, this.beanName);
return super.invoke(mi);
}
@@ -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.
@@ -53,28 +53,29 @@ public abstract class ScopedProxyUtils {
// Create a scoped proxy definition for the original bean name,
// "hiding" the target bean in an internal target definition.
RootBeanDefinition scopedProxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
scopedProxyDefinition.setOriginatingBeanDefinition(definition.getBeanDefinition());
scopedProxyDefinition.setSource(definition.getSource());
scopedProxyDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
proxyDefinition.setOriginatingBeanDefinition(definition.getBeanDefinition());
proxyDefinition.setSource(definition.getSource());
proxyDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String targetBeanName = getTargetBeanName(originalBeanName);
scopedProxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
if (proxyTargetClass) {
targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// ScopedFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
}
else {
scopedProxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
}
// Copy autowire settings from original bean definition.
proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
proxyDefinition.setPrimary(targetDefinition.isPrimary());
if (targetDefinition instanceof AbstractBeanDefinition) {
scopedProxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
}
scopedProxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
scopedProxyDefinition.setPrimary(targetDefinition.isPrimary());
// The target bean should be ignored in favor of the scoped proxy.
targetDefinition.setAutowireCandidate(false);
targetDefinition.setPrimary(false);
@@ -84,7 +85,7 @@ public abstract class ScopedProxyUtils {
// Return the scoped proxy definition as primary bean definition
// (potentially an inner bean).
return new BeanDefinitionHolder(scopedProxyDefinition, originalBeanName, definition.getAliases());
return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}
/**
@@ -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.
@@ -85,7 +85,7 @@ public abstract class AopUtils {
* Check whether the specified class is a CGLIB-generated class.
* @param clazz the class to check
*/
public static boolean isCglibProxyClass(Class clazz) {
public static boolean isCglibProxyClass(Class<?> clazz) {
return (clazz != null && isCglibProxyClassName(clazz.getName()));
}
@@ -102,18 +102,20 @@ public abstract class AopUtils {
* which might be an AOP proxy.
* <p>Returns the target class for an AOP proxy and the plain class else.
* @param candidate the instance to check (might be an AOP proxy)
* @return the target class (or the plain class of the given object as fallback)
* @return the target class (or the plain class of the given object as fallback;
* never <code>null</code>)
* @see org.springframework.aop.TargetClassAware#getTargetClass()
*/
public static Class getTargetClass(Object candidate) {
public static Class<?> getTargetClass(Object candidate) {
Assert.notNull(candidate, "Candidate object must not be null");
Class<?> result = null;
if (candidate instanceof TargetClassAware) {
return ((TargetClassAware) candidate).getTargetClass();
result = ((TargetClassAware) candidate).getTargetClass();
}
if (isCglibProxy(candidate)) {
return candidate.getClass().getSuperclass();
if (result == null) {
result = (isCglibProxy(candidate) ? candidate.getClass().getSuperclass() : candidate.getClass());
}
return candidate.getClass();
return result;
}
/**
@@ -165,7 +167,7 @@ public abstract class AopUtils {
* <code>targetClass</code> doesn't implement it or is <code>null</code>
* @see org.springframework.util.ClassUtils#getMostSpecificMethod
*/
public static Method getMostSpecificMethod(Method method, Class targetClass) {
public static Method getMostSpecificMethod(Method method, Class<?> targetClass) {
Method resolvedMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
// If we are dealing with method with generic parameters, find the original method.
return BridgeMethodResolver.findBridgedMethod(resolvedMethod);
@@ -180,7 +182,7 @@ public abstract class AopUtils {
* @param targetClass the class to test
* @return whether the pointcut can apply on any method
*/
public static boolean canApply(Pointcut pc, Class targetClass) {
public static boolean canApply(Pointcut pc, Class<?> targetClass) {
return canApply(pc, targetClass, false);
}
@@ -194,7 +196,7 @@ public abstract class AopUtils {
* for this bean includes any introductions
* @return whether the pointcut can apply on any method
*/
public static boolean canApply(Pointcut pc, Class targetClass, boolean hasIntroductions) {
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
@@ -207,7 +209,7 @@ public abstract class AopUtils {
Set<Class> classes = new HashSet<Class>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Class clazz : classes) {
for (Class<?> clazz : classes) {
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if ((introductionAwareMethodMatcher != null &&
@@ -229,7 +231,7 @@ public abstract class AopUtils {
* @param targetClass class we're testing
* @return whether the pointcut can apply on any method
*/
public static boolean canApply(Advisor advisor, Class targetClass) {
public static boolean canApply(Advisor advisor, Class<?> targetClass) {
return canApply(advisor, targetClass, false);
}
@@ -243,7 +245,7 @@ public abstract class AopUtils {
* any introductions
* @return whether the pointcut can apply on any method
*/
public static boolean canApply(Advisor advisor, Class targetClass, boolean hasIntroductions) {
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
@@ -265,7 +267,7 @@ public abstract class AopUtils {
* @return sublist of Advisors that can apply to an object of the given class
* (may be the incoming List as-is)
*/
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class clazz) {
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
@@ -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.
@@ -16,15 +16,14 @@
package org.springframework.aop.aspectj.annotation;
import static org.junit.Assert.*;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import static org.junit.Assert.*;
import org.junit.Ignore;
import org.junit.Test;
import test.aop.PerThisAspect;
import test.util.SerializationTestUtils;
/**
* @author Rob Harrop
@@ -76,6 +75,7 @@ public final class AspectProxyFactoryTests {
}
@Test
@Ignore // InstantiationModelAwarePointcutAdvisorImpl not serializable yet
public void testWithInstance() throws Exception {
MultiplyReturnValue aspect = new MultiplyReturnValue();
int multiple = 3;
@@ -88,8 +88,10 @@ public final class AspectProxyFactoryTests {
proxyFactory.addAspect(aspect);
ITestBean proxy = proxyFactory.getProxy();
assertEquals(target.getAge() * multiple, proxy.getAge());
ITestBean serializedProxy = (ITestBean) SerializationTestUtils.serializeAndDeserialize(proxy);
assertEquals(target.getAge() * multiple, serializedProxy.getAge());
}
@Test(expected=IllegalArgumentException.class)
+4 -4
View File
@@ -8,10 +8,10 @@ Import-Template:
org.aopalliance.*;version="[1.0.0, 2.0.0)",
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
org.apache.commons.pool.*;version="[1.3.0, 2.0.0)";resolution:=optional,
org.aspectj.*;version="[1.5.4, 2.0.0)";resolution:=optional,
org.springframework.beans.*;version="[3.0.0, 3.0.1)";resolution:=optional,
org.springframework.core.*;version="[3.0.0, 3.0.1)",
org.springframework.util.*;version="[3.0.0, 3.0.1)",
org.aspectj.*;version=${aj.osgi.range};resolution:=optional,
org.springframework.beans.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.core.*;version=${spring.osgi.range},
org.springframework.util.*;version=${spring.osgi.range},
org.w3c.dom.*;version="0";resolution:=optional
Ignored-Existing-Headers:
Bnd-LastModified,
+2 -2
View File
@@ -4,12 +4,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-asm</artifactId>
<packaging>jar</packaging>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
</parent>
+14 -14
View File
@@ -4,12 +4,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<packaging>jar</packaging>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
</parent>
<dependencies>
@@ -32,22 +32,22 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
<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>
<optional>true</optional>
<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>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
@@ -151,7 +151,7 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
expectations.verify();
}
Object around() : methodToMock() {
Object around() : methodToMock() && cflowbelow(mockStaticsTestMethod()) {
if (recording) {
expectations.expectCall(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
// Return value doesn't matter
+5 -5
View File
@@ -4,11 +4,11 @@ Bundle-Vendor: SpringSource
Bundle-ManifestVersion: 2
Import-Template:
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
org.aspectj.*;version="[1.5.4, 2.0.0)";resolution:=optional,
org.springframework.beans.*;version="[3.0.0, 3.0.1)",
org.springframework.transaction.*;version="[3.0.0, 3.0.1)";resolution:=optional,
org.springframework.orm.jpa.*;version="[3.0.0, 3.0.1)";resolution:=optional,
org.springframework.dao.*;version="[3.0.0, 3.0.1)";resolution:=optional
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.orm.jpa.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.dao.*;version=${spring.osgi.range};resolution:=optional
Ignored-Existing-Headers:
Bnd-LastModified,
Import-Package,
+2 -2
View File
@@ -4,12 +4,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<packaging>jar</packaging>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
</parent>
<dependencies>
@@ -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.
@@ -389,8 +389,17 @@ public abstract class BeanUtils {
}
ClassLoader cl = targetType.getClassLoader();
if (cl == null) {
cl = ClassLoader.getSystemClassLoader();
if (cl == null) {
try {
cl = ClassLoader.getSystemClassLoader();
if (cl == null) {
return null;
}
}
catch (Throwable ex) {
// e.g. AccessControlException on Google App Engine
if (logger.isDebugEnabled()) {
logger.debug("Could not access system ClassLoader: " + ex);
}
return null;
}
}
@@ -398,8 +407,10 @@ public abstract class BeanUtils {
try {
Class<?> editorClass = cl.loadClass(editorName);
if (!PropertyEditor.class.isAssignableFrom(editorClass)) {
logger.warn("Editor class [" + editorName +
"] does not implement [java.beans.PropertyEditor] interface");
if (logger.isWarnEnabled()) {
logger.warn("Editor class [" + editorName +
"] does not implement [java.beans.PropertyEditor] interface");
}
unknownEditorTypes.put(targetType, Boolean.TRUE);
return null;
}
@@ -44,6 +44,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.PropertyTypeDescriptor;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -101,6 +102,11 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
private TypeConverterDelegate typeConverterDelegate;
/**
* The security context used for invoking the property methods
*/
private AccessControlContext acc;
/**
* Cached introspections results for this object, to prevent encountering
* the cost of JavaBeans introspection every time.
@@ -112,9 +118,6 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
*/
private Map<String, BeanWrapperImpl> nestedBeanWrappers;
/** The security context used for invoking the property methods */
private AccessControlContext acc;
private boolean autoGrowNestedPaths = false;
@@ -216,16 +219,6 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
setIntrospectionClass(object.getClass());
}
/**
* Set the security context used during the invocation of the wrapped instance methods.
* Can be null.
*
* @param acc
*/
public void setSecurityContext(AccessControlContext acc) {
this.acc = acc;
}
public final Object getWrappedInstance() {
return this.object;
}
@@ -274,6 +267,22 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
return this.autoGrowNestedPaths;
}
/**
* Set the security context used during the invocation of the wrapped instance methods.
* Can be null.
*/
public void setSecurityContext(AccessControlContext acc) {
this.acc = acc;
}
/**
* Return the security context used during the invocation of the wrapped instance methods.
* Can be null.
*/
public AccessControlContext getSecurityContext() {
return this.acc;
}
/**
* Set the class to introspect.
* Needs to be called when the target object changes.
@@ -360,10 +369,10 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
if (pd != null) {
Class type = getPropertyType(propertyName);
if (pd.getReadMethod() != null) {
return new BeanTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), type);
return new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), type);
}
else if (pd.getWriteMethod() != null) {
return new BeanTypeDescriptor(pd, BeanUtils.getWriteMethodParameter(pd), type);
return new PropertyTypeDescriptor(pd, BeanUtils.getWriteMethodParameter(pd), type);
}
}
}
@@ -772,7 +781,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
"Getter for property '" + actualName + "' threw exception", ex);
}
catch(IllegalAccessException ex) {
catch (IllegalAccessException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Illegal attempt to get property '" + actualName + "' threw exception", ex);
}
@@ -804,7 +813,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
}
setPropertyValue(name, newArray);
return newArray;
} else {
}
else {
return array;
}
}
@@ -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.
@@ -22,6 +22,8 @@ import java.util.HashMap;
import java.util.Map;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
@@ -125,10 +127,11 @@ public class DirectFieldAccessor extends AbstractPropertyAccessor {
Object convertedValue = this.typeConverterDelegate.convertIfNecessary(oldValue, newValue, field);
field.set(this.target, convertedValue);
}
catch (IllegalAccessException ex) {
throw new InvalidPropertyException(this.target.getClass(), propertyName, "Field is not accessible", ex);
catch (ConverterNotFoundException ex) {
PropertyChangeEvent pce = new PropertyChangeEvent(this.target, propertyName, oldValue, newValue);
throw new ConversionNotSupportedException(pce, field.getType(), ex);
}
catch (IllegalArgumentException ex) {
catch (ConversionException ex) {
PropertyChangeEvent pce = new PropertyChangeEvent(this.target, propertyName, oldValue, newValue);
throw new TypeMismatchException(pce, field.getType(), ex);
}
@@ -136,6 +139,13 @@ public class DirectFieldAccessor extends AbstractPropertyAccessor {
PropertyChangeEvent pce = new PropertyChangeEvent(this.target, propertyName, oldValue, newValue);
throw new ConversionNotSupportedException(pce, field.getType(), ex);
}
catch (IllegalArgumentException ex) {
PropertyChangeEvent pce = new PropertyChangeEvent(this.target, propertyName, oldValue, newValue);
throw new TypeMismatchException(pce, field.getType(), ex);
}
catch (IllegalAccessException ex) {
throw new InvalidPropertyException(this.target.getClass(), propertyName, "Field is not accessible", ex);
}
}
public <T> T convertIfNecessary(
@@ -33,6 +33,7 @@ import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.PropertyTypeDescriptor;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@@ -152,7 +153,7 @@ class TypeConverterDelegate {
throws IllegalArgumentException {
return convertIfNecessary(descriptor.getName(), oldValue, newValue, descriptor.getPropertyType(),
new BeanTypeDescriptor(descriptor));
new PropertyTypeDescriptor(descriptor, BeanUtils.getWriteMethodParameter(descriptor)));
}
/**
@@ -195,8 +196,9 @@ class TypeConverterDelegate {
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
if (editor == null && conversionService != null && convertedValue != null) {
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(convertedValue);
if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
return (T) conversionService.convert(convertedValue, sourceTypeDesc, typeDescriptor);
TypeDescriptor targetTypeDesc = typeDescriptor.forElementType(requiredType);
if (conversionService.canConvert(sourceTypeDesc, targetTypeDesc)) {
return (T) conversionService.convert(convertedValue, sourceTypeDesc, targetTypeDesc);
}
}
@@ -204,8 +206,8 @@ class TypeConverterDelegate {
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
if (requiredType != null && Collection.class.isAssignableFrom(requiredType) &&
convertedValue instanceof String && typeDescriptor.getMethodParameter() != null) {
Class elementType = GenericCollectionTypeResolver.getCollectionParameterType(typeDescriptor.getMethodParameter());
if (elementType != null && Enum.class.isAssignableFrom(elementType)) {
Class elemType = GenericCollectionTypeResolver.getCollectionParameterType(typeDescriptor.getMethodParameter());
if (elemType != null && Enum.class.isAssignableFrom(elemType)) {
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
}
@@ -348,8 +350,8 @@ class TypeConverterDelegate {
*/
protected PropertyEditor findDefaultEditor(Class requiredType, TypeDescriptor typeDescriptor) {
PropertyEditor editor = null;
if (typeDescriptor instanceof BeanTypeDescriptor) {
PropertyDescriptor pd = ((BeanTypeDescriptor) typeDescriptor).getPropertyDescriptor();
if (typeDescriptor instanceof PropertyTypeDescriptor) {
PropertyDescriptor pd = ((PropertyTypeDescriptor) typeDescriptor).getPropertyDescriptor();
editor = pd.createPropertyEditor(this.targetObject);
}
if (editor == null && requiredType != null) {
@@ -518,6 +520,10 @@ class TypeConverterDelegate {
Collection original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
boolean originalAllowed = requiredType.isInstance(original);
if (!originalAllowed && !Collection.class.isAssignableFrom(requiredType)) {
return original;
}
MethodParameter methodParam = typeDescriptor.getMethodParameter();
Class elementType = null;
if (methodParam != null) {
@@ -571,8 +577,8 @@ class TypeConverterDelegate {
if (methodParam != null) {
methodParam.increaseNestingLevel();
}
Object convertedElement =
convertIfNecessary(indexedPropertyName, null, element, elementType, typeDescriptor);
Object convertedElement = convertIfNecessary(
indexedPropertyName, null, element, elementType, typeDescriptor);
if (methodParam != null) {
methodParam.decreaseNestingLevel();
}
@@ -592,8 +598,14 @@ class TypeConverterDelegate {
}
@SuppressWarnings("unchecked")
protected Map convertToTypedMap(Map original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
protected Map convertToTypedMap(
Map original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
boolean originalAllowed = requiredType.isInstance(original);
if (!originalAllowed && !Map.class.isAssignableFrom(requiredType)) {
return original;
}
Class keyType = null;
Class valueType = null;
MethodParameter methodParam = typeDescriptor.getMethodParameter();
@@ -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.
@@ -153,8 +153,14 @@ public interface BeanFactory {
* Return the bean instance that uniquely matches the given object type, if any.
* @param requiredType type the bean must match; can be an interface or superclass.
* {@literal null} is disallowed.
* @return bean matching required type
* <p>This method goes into {@link ListableBeanFactory} by-type lookup territory
* but may also be translated into a conventional by-name lookup based on the name
* of the given type. For more extensive retrieval operations across sets of beans,
* use {@link ListableBeanFactory} and/or {@link BeanFactoryUtils}.
* @return an instance of the single bean matching the required type
* @throws NoSuchBeanDefinitionException if there is not exactly one matching bean found
* @since 3.0
* @see ListableBeanFactory
*/
<T> T getBean(Class<T> requiredType) throws BeansException;
@@ -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.
@@ -193,7 +193,7 @@ public abstract class AbstractFactoryBean<T>
* interface, for a consistent offering of abstract template methods.
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
public abstract Class<? extends T> getObjectType();
public abstract Class<?> getObjectType();
/**
* Template method that subclasses must override to construct
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 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.
@@ -48,7 +48,8 @@ public interface BeanPostProcessor {
* The returned bean instance may be a wrapper around the original.
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one
* @return the bean instance to use, either the original or a wrapped one; if
* <code>null</code>, no subsequent BeanPostProcessors will be invoked
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
*/
@@ -68,7 +69,8 @@ public interface BeanPostProcessor {
* in contrast to all other BeanPostProcessor callbacks.
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one
* @return the bean instance to use, either the original or a wrapped one; if
* <code>null</code>, no subsequent BeanPostProcessors will be invoked
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
* @see org.springframework.beans.factory.FactoryBean
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 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,7 +16,10 @@
package org.springframework.beans.factory.config;
import java.io.Serializable;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.util.Assert;
@@ -41,7 +44,7 @@ import org.springframework.util.Assert;
* <pre class="code">&lt;beans&gt;
*
* &lt;!-- Prototype bean since we have state --&gt;
* &lt;bean id="myService" class="a.b.c.MyService" singleton="false"/&gt;
* &lt;bean id="myService" class="a.b.c.MyService" scope="prototype"/&gt;
*
* &lt;bean id="myServiceFactory"
* class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean"&gt;
@@ -63,9 +66,9 @@ import org.springframework.util.Assert;
*
* public class MyClientBean {
*
* private ObjectFactory myServiceFactory;
* private ObjectFactory&lt;MyService&gt; myServiceFactory;
*
* public void setMyServiceFactory(ObjectFactory myServiceFactory) {
* public void setMyServiceFactory(ObjectFactory&lt;MyService&gt; myServiceFactory) {
* this.myServiceFactory = myServiceFactory;
* }
*
@@ -91,20 +94,17 @@ import org.springframework.util.Assert;
* @see org.springframework.beans.factory.ObjectFactory
* @see ServiceLocatorFactoryBean
*/
public class ObjectFactoryCreatingFactoryBean extends AbstractFactoryBean {
public class ObjectFactoryCreatingFactoryBean extends AbstractFactoryBean<ObjectFactory> {
private String targetBeanName;
/**
* Set the name of the target bean.
* <p>The target does not <i>have</> to be a prototype bean, but realisticially
* always will be (because if the target bean were a singleton, then said
* singleton bean could simply be injected straight into the dependent object,
* thus obviating the need for the extra level of indirection afforded by
* the approach encapsulated by this class). Please note that no exception
* will be thrown if the supplied <code>targetBeanName</code> does not
* reference a prototype bean.
* <p>The target does not <i>have</> to be a non-singleton bean, but realisticially
* always will be (because if the target bean were a singleton, then said singleton
* bean could simply be injected straight into the dependent object, thus obviating
* the need for the extra level of indirection afforded by this factory approach).
*/
public void setTargetBeanName(String targetBeanName) {
this.targetBeanName = targetBeanName;
@@ -123,22 +123,28 @@ public class ObjectFactoryCreatingFactoryBean extends AbstractFactoryBean {
}
@Override
protected Object createInstance() {
return new ObjectFactory() {
public Object getObject() throws BeansException {
return getTargetBean(targetBeanName);
}
};
protected ObjectFactory createInstance() {
return new TargetBeanObjectFactory(getBeanFactory(), this.targetBeanName);
}
/**
* Template method for obtaining a target bean instance.
* Called by the exposed ObjectFactory's <code>getObject()</code> method.
* @param targetBeanName the name of the target bean
* @return the target bean instance
* Independent inner class - for serialization purposes.
*/
protected Object getTargetBean(String targetBeanName) {
return getBeanFactory().getBean(targetBeanName);
private static class TargetBeanObjectFactory implements ObjectFactory, Serializable {
private final BeanFactory beanFactory;
private final String targetBeanName;
public TargetBeanObjectFactory(BeanFactory beanFactory, String targetBeanName) {
this.beanFactory = beanFactory;
this.targetBeanName = targetBeanName;
}
public Object getObject() throws BeansException {
return this.beanFactory.getBean(this.targetBeanName);
}
}
}
@@ -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.
@@ -193,7 +193,8 @@ public class PropertyPathFactoryBean implements FactoryBean<Object>, BeanNameAwa
public Object getObject() throws BeansException {
BeanWrapper target = this.targetBeanWrapper;
if (target != null) {
if (logger.isWarnEnabled() && this.beanFactory instanceof ConfigurableBeanFactory &&
if (logger.isWarnEnabled() && this.targetBeanName != null &&
this.beanFactory instanceof ConfigurableBeanFactory &&
((ConfigurableBeanFactory) this.beanFactory).isCurrentlyInCreation(this.targetBeanName)) {
logger.warn("Target bean '" + this.targetBeanName + "' is still in creation due to a circular " +
"reference - obtained value for property '" + this.propertyPath + "' may be outdated!");
@@ -0,0 +1,95 @@
/*
* 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.beans.factory.config;
import java.io.Serializable;
import javax.inject.Provider;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.util.Assert;
/**
* A {@link org.springframework.beans.factory.FactoryBean} implementation that
* returns a value which is a JSR-330 {@link javax.inject.Provider} that in turn
* returns a bean sourced from a {@link org.springframework.beans.factory.BeanFactory}.
*
* <p>This is basically a JSR-330 compliant variant of Spring's good old
* {@link ObjectFactoryCreatingFactoryBean}. It can be used for traditional
* external dependency injection configuration that targets a property or
* constructor argument of type <code>javax.inject.Provider</code>, as an
* alternative to JSR-330's <code>@Inject</code> annotation-driven approach.
*
* @author Juergen Hoeller
* @since 3.0.2
* @see javax.inject.Provider
* @see ObjectFactoryCreatingFactoryBean
*/
public class ProviderCreatingFactoryBean extends AbstractFactoryBean<Provider> {
private String targetBeanName;
/**
* Set the name of the target bean.
* <p>The target does not <i>have</> to be a non-singleton bean, but realisticially
* always will be (because if the target bean were a singleton, then said singleton
* bean could simply be injected straight into the dependent object, thus obviating
* the need for the extra level of indirection afforded by this factory approach).
*/
public void setTargetBeanName(String targetBeanName) {
this.targetBeanName = targetBeanName;
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.hasText(this.targetBeanName, "Property 'targetBeanName' is required");
super.afterPropertiesSet();
}
@Override
public Class getObjectType() {
return Provider.class;
}
@Override
protected Provider createInstance() {
return new TargetBeanProvider(getBeanFactory(), this.targetBeanName);
}
/**
* Independent inner class - for serialization purposes.
*/
private static class TargetBeanProvider implements Provider, Serializable {
private final BeanFactory beanFactory;
private final String targetBeanName;
public TargetBeanProvider(BeanFactory beanFactory, String targetBeanName) {
this.beanFactory = beanFactory;
this.targetBeanName = targetBeanName;
}
public Object get() throws BeansException {
return this.beanFactory.getBean(this.targetBeanName);
}
}
}
@@ -392,6 +392,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
@@ -402,6 +405,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
@@ -682,11 +688,14 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
*/
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return exposedObject;
}
}
}
}
@@ -1130,7 +1139,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass());
DependencyDescriptor desc = new DependencyDescriptor(methodParam, false, eager);
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
pvs.add(propertyName, autowiredArgument);
@@ -1553,4 +1562,21 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
this.factoryBeanInstanceCache.remove(beanName);
}
/**
* Special DependencyDescriptor variant for autowire="byType".
* Always optional; never considering the parameter name for choosing a primary candidate.
*/
private static class AutowireByTypeDependencyDescriptor extends DependencyDescriptor {
public AutowireByTypeDependencyDescriptor(MethodParameter methodParameter, boolean eager) {
super(methodParameter, false, eager);
}
@Override
public String getDependencyName() {
return null;
}
}
}
@@ -57,6 +57,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanExpressionResolver;
import org.springframework.beans.factory.config.BeanPostProcessor;
@@ -222,7 +223,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
* @throws BeansException if the bean could not be created
*/
@SuppressWarnings("unchecked")
private <T> T doGetBean(
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
@@ -473,7 +474,20 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
return parentBeanFactory.isTypeMatch(originalBeanName(name), targetType);
}
// Retrieve corresponding bean definition.
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Check decorated bean definition, if any: We assume it'll be easier
// to determine the decorated bean's type than the proxy's type.
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
Class targetClass = predictBeanType(dbd.getBeanName(), tbd, FactoryBean.class, typeToMatch);
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
return typeToMatch.isAssignableFrom(targetClass);
}
}
Class beanClass = predictBeanType(beanName, mbd, FactoryBean.class, typeToMatch);
if (beanClass == null) {
return false;
@@ -901,6 +915,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
}
public boolean isCurrentlyInCreation(String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
return isSingletonCurrentlyInCreation(beanName) || isPrototypeCurrentlyInCreation(beanName);
}
@@ -1241,7 +1256,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
if (this.beanExpressionResolver == null) {
return value;
}
Scope scope = getRegisteredScope(beanDefinition.getScope());
Scope scope = (beanDefinition != null ? getRegisteredScope(beanDefinition.getScope()) : null);
return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
}
@@ -16,6 +16,8 @@
package org.springframework.beans.factory.support;
import static org.springframework.util.StringUtils.collectionToCommaDelimitedString;
import java.beans.ConstructorProperties;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
@@ -44,6 +46,7 @@ import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
@@ -51,6 +54,7 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.MethodInvoker;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* Helper class for resolving constructors and factory methods.
@@ -497,12 +501,25 @@ class ConstructorResolver {
}
if (factoryMethodToUse == null) {
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();
argTypes.add(argType);
}
argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"No matching factory method found: " +
(mbd.getFactoryBeanName() != null ?
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
"factory method '" + mbd.getFactoryMethodName() + "'. " +
"Check that a method of the specified name exists and that it is " +
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
"Check that a method with the specified name " +
(hasArgs ? "and arguments " : "") +
"exists and that it is " +
(isStatic ? "static" : "non-static") + ".");
}
else if (void.class.equals(factoryMethodToUse.getReturnType())) {
@@ -262,6 +262,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
public boolean containsBeanDefinition(String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
return this.beanDefinitionMap.containsKey(beanName);
}
@@ -574,7 +575,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "'beanName' must not be empty");
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
@@ -693,7 +694,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (value != null) {
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value);
value = evaluateBeanDefinitionString(strVal, getMergedBeanDefinition(beanName));
BeanDefinition bd = (containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
return converter.convertIfNecessary(value, type);
@@ -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.
@@ -123,8 +123,6 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
final FactoryBean factory, final String beanName, final boolean shouldPostProcess)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
@@ -135,7 +133,8 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
return factory.getObject();
}
}, acc);
} catch (PrivilegedActionException pae) {
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
@@ -24,6 +24,7 @@ import java.util.Set;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.util.Assert;
@@ -53,6 +54,8 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
private final Set<String> externallyManagedDestroyMethods = Collections.synchronizedSet(new HashSet<String>());
private BeanDefinitionHolder decoratedDefinition;
boolean isFactoryMethodUnique;
/** Package-visible field for caching the resolved constructor or factory method */
@@ -75,7 +78,6 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
final Object postProcessingLock = new Object();
/**
* Create a new RootBeanDefinition, to be configured through its bean
* properties and configuration methods.
@@ -224,7 +226,9 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
RootBeanDefinition(BeanDefinition original) {
super(original);
if (original instanceof RootBeanDefinition) {
this.isFactoryMethodUnique = ((RootBeanDefinition) original).isFactoryMethodUnique;
RootBeanDefinition originalRbd = (RootBeanDefinition) original;
this.decoratedDefinition = originalRbd.decoratedDefinition;
this.isFactoryMethodUnique = originalRbd.isFactoryMethodUnique;
}
}
@@ -289,6 +293,14 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
return this.externallyManagedDestroyMethods.contains(destroyMethod);
}
public void setDecoratedDefinition(BeanDefinitionHolder decoratedDefinition) {
this.decoratedDefinition = decoratedDefinition;
}
public BeanDefinitionHolder getDecoratedDefinition() {
return this.decoratedDefinition;
}
@Override
public RootBeanDefinition cloneBeanDefinition() {
@@ -16,15 +16,6 @@
package org.springframework.beans.factory;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.security.AccessControlContext;
@@ -40,12 +31,19 @@ import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
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.Test;
import test.beans.DerivedTestBean;
import test.beans.DummyFactory;
import test.beans.ITestBean;
import test.beans.LifecycleBean;
import test.beans.NestedTestBean;
import test.beans.TestBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.NotWritablePropertyException;
@@ -72,6 +70,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ConstructorDependenciesBean;
import org.springframework.beans.factory.xml.DependenciesBean;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.ConversionServiceFactory;
@@ -80,13 +79,6 @@ import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.util.StopWatch;
import test.beans.DerivedTestBean;
import test.beans.DummyFactory;
import test.beans.ITestBean;
import test.beans.LifecycleBean;
import test.beans.NestedTestBean;
import test.beans.TestBean;
/**
* Tests properties population and autowire behavior.
*
@@ -1103,7 +1095,7 @@ public final class DefaultListableBeanFactoryTests {
@Test
public void testAutowireWithNoDependencies() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("rod", bd);
assertEquals(1, lbf.getBeanDefinitionCount());
Object registered = lbf.autowire(NoDependencies.class, AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT, false);
@@ -1180,7 +1172,7 @@ public final class DefaultListableBeanFactoryTests {
@Test
public void testAutowireConstructor() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("spouse", bd);
ConstructorDependenciesBean bean = (ConstructorDependenciesBean)
lbf.autowire(ConstructorDependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, true);
@@ -1192,7 +1184,7 @@ public final class DefaultListableBeanFactoryTests {
@Test
public void testAutowireBeanByName() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("spouse", bd);
DependenciesBean bean = (DependenciesBean)
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true);
@@ -1204,7 +1196,7 @@ public final class DefaultListableBeanFactoryTests {
@Test
public void testAutowireBeanByNameWithDependencyCheck() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("spous", bd);
try {
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true);
@@ -1218,7 +1210,7 @@ public final class DefaultListableBeanFactoryTests {
@Test
public void testAutowireBeanByNameWithNoDependencyCheck() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("spous", bd);
DependenciesBean bean = (DependenciesBean)
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
@@ -1228,7 +1220,7 @@ public final class DefaultListableBeanFactoryTests {
@Test
public void testAutowireBeanByType() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("test", bd);
DependenciesBean bean = (DependenciesBean)
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
@@ -1245,7 +1237,7 @@ public final class DefaultListableBeanFactoryTests {
@Test
public void testAutowireBeanWithFactoryBeanByType() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(LazyInitFactory.class, new MutablePropertyValues());
RootBeanDefinition bd = new RootBeanDefinition(LazyInitFactory.class);
lbf.registerBeanDefinition("factoryBean", bd);
LazyInitFactory factoryBean = (LazyInitFactory) lbf.getBean("&factoryBean");
assertNotNull("The FactoryBean should have been registered.", factoryBean);
@@ -1264,7 +1256,7 @@ public final class DefaultListableBeanFactoryTests {
@Test(expected=TypeMismatchException.class)
public void testAutowireBeanWithFactoryBeanByName() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(LazyInitFactory.class, new MutablePropertyValues());
RootBeanDefinition bd = new RootBeanDefinition(LazyInitFactory.class);
lbf.registerBeanDefinition("factoryBean", bd);
LazyInitFactory factoryBean = (LazyInitFactory) lbf.getBean("&factoryBean");
assertNotNull("The FactoryBean should have been registered.", factoryBean);
@@ -1274,10 +1266,10 @@ public final class DefaultListableBeanFactoryTests {
@Test
public void testAutowireBeanByTypeWithTwoMatches() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues());
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class, new MutablePropertyValues());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("test", bd);
lbf.registerBeanDefinition("test2", bd2);
lbf.registerBeanDefinition("spouse", bd2);
try {
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
fail("Should have thrown UnsatisfiedDependencyException");
@@ -1285,7 +1277,26 @@ public final class DefaultListableBeanFactoryTests {
catch (UnsatisfiedDependencyException ex) {
// expected
assertTrue(ex.getMessage().indexOf("test") != -1);
assertTrue(ex.getMessage().indexOf("test2") != -1);
assertTrue(ex.getMessage().indexOf("spouse") != -1);
}
}
@Test
public void testAutowireBeanByTypeWithTwoMatchesAndParameterNameDiscovery() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
lbf.setParameterNameDiscoverer(new LocalVariableTableParameterNameDiscoverer());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("test", bd);
lbf.registerBeanDefinition("spouse", bd2);
try {
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
fail("Should have thrown UnsatisfiedDependencyException");
}
catch (UnsatisfiedDependencyException ex) {
// expected
assertTrue(ex.getMessage().indexOf("test") != -1);
assertTrue(ex.getMessage().indexOf("spouse") != -1);
}
}
@@ -1312,7 +1323,7 @@ public final class DefaultListableBeanFactoryTests {
@Test
public void testAutowireExistingBeanByName() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("spouse", bd);
DependenciesBean existingBean = new DependenciesBean();
lbf.autowireBeanProperties(existingBean, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true);
@@ -1324,7 +1335,7 @@ public final class DefaultListableBeanFactoryTests {
@Test
public void testAutowireExistingBeanByNameWithDependencyCheck() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("spous", bd);
DependenciesBean existingBean = new DependenciesBean();
try {
@@ -1339,7 +1350,7 @@ public final class DefaultListableBeanFactoryTests {
@Test
public void testAutowireExistingBeanByNameWithNoDependencyCheck() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("spous", bd);
DependenciesBean existingBean = new DependenciesBean();
lbf.autowireBeanProperties(existingBean, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
@@ -1349,7 +1360,7 @@ public final class DefaultListableBeanFactoryTests {
@Test
public void testAutowireExistingBeanByType() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("test", bd);
DependenciesBean existingBean = new DependenciesBean();
lbf.autowireBeanProperties(existingBean, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
@@ -1431,7 +1442,7 @@ public final class DefaultListableBeanFactoryTests {
@Test
public void testConfigureBeanWithAutowiring() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("spouse", bd);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("age", "99");
@@ -0,0 +1,93 @@
package org.springframework.beans.factory;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
/**
* SPR-5475 exposed the fact that the error message displayed when incorrectly
* invoking a factory method is not instructive to the user and rather misleading.
*
* @author Chris Beams
*/
public class Spr5475Tests {
@Test
public void noArgFactoryMethodInvokedWithOneArg() {
assertExceptionMessageForMisconfiguredFactoryMethod(
rootBeanDefinition(Foo.class)
.setFactoryMethod("noArgFactory")
.addConstructorArgValue("bogusArg").getBeanDefinition(),
"Error creating bean with name 'foo': No matching factory method found: factory method 'noArgFactory(String)'. " +
"Check that a method with the specified name and arguments exists and that it is static.");
}
@Test
public void noArgFactoryMethodInvokedWithTwoArgs() {
assertExceptionMessageForMisconfiguredFactoryMethod(
rootBeanDefinition(Foo.class)
.setFactoryMethod("noArgFactory")
.addConstructorArgValue("bogusArg1")
.addConstructorArgValue("bogusArg2".getBytes()).getBeanDefinition(),
"Error creating bean with name 'foo': No matching factory method found: factory method 'noArgFactory(String,byte[])'. " +
"Check that a method with the specified name and arguments exists and that it is static.");
}
@Test
public void noArgFactoryMethodInvokedWithTwoArgsAndTypesSpecified() {
RootBeanDefinition def = new RootBeanDefinition(Foo.class);
def.setFactoryMethodName("noArgFactory");
ConstructorArgumentValues cav = new ConstructorArgumentValues();
cav.addIndexedArgumentValue(0, "bogusArg1", CharSequence.class.getName());
cav.addIndexedArgumentValue(1, "bogusArg2".getBytes());
def.setConstructorArgumentValues(cav);
assertExceptionMessageForMisconfiguredFactoryMethod(
def,
"Error creating bean with name 'foo': No matching factory method found: factory method 'noArgFactory(CharSequence,byte[])'. " +
"Check that a method with the specified name and arguments exists and that it is static.");
}
private void assertExceptionMessageForMisconfiguredFactoryMethod(BeanDefinition bd, String expectedMessage) {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition("foo", bd);
try {
factory.preInstantiateSingletons();
fail("should have failed with BeanCreationException due to incorrectly invoked factory method");
} catch (BeanCreationException ex) {
assertThat(ex.getMessage(), equalTo(expectedMessage));
}
}
@Test
public void singleArgFactoryMethodInvokedWithNoArgs() {
// calling a factory method that accepts arguments without any arguments emits an exception unlike cases
// where a no-arg factory method is called with arguments. Adding this test just to document the difference
assertExceptionMessageForMisconfiguredFactoryMethod(
rootBeanDefinition(Foo.class)
.setFactoryMethod("singleArgFactory").getBeanDefinition(),
"Error creating bean with name 'foo': " +
"Unsatisfied dependency expressed through constructor argument with index 0 of type [java.lang.String]: " +
"Ambiguous factory method argument types - did you specify the correct bean references as factory method arguments?");
}
static class Foo {
static Foo noArgFactory() {
return new Foo();
}
static Foo singleArgFactory(String arg) {
return new Foo();
}
}
}
@@ -1,19 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<!--
Test data for ObjectFactoryCreatingFactoryBeanTests
-->
<beans>
<bean id="prototypeTarget" class="java.util.Date" scope="prototype"/>
<bean id="prototype" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName"><idref local="prototypeTarget"/></property>
<bean id="prototypeFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="prototypeTarget"/>
</bean>
<bean id="testBean" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBeanTests$TestBean">
<property name="objectFactory"><ref local="prototype"/></property>
<bean id="factoryTestBean" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBeanTests$FactoryTestBean">
<property name="objectFactory" ref="prototypeFactory"/>
</bean>
<bean id="prototypeProvider" class="org.springframework.beans.factory.config.ProviderCreatingFactoryBean">
<property name="targetBeanName" value="prototypeTarget"/>
</bean>
<bean id="providerTestBean" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBeanTests$ProviderTestBean">
<property name="provider" ref="prototypeProvider"/>
</bean>
</beans>
@@ -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.
@@ -16,43 +16,49 @@
package org.springframework.beans.factory.config;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import static test.util.TestResourceUtils.qualifiedResource;
import java.util.Date;
import javax.inject.Provider;
import static org.easymock.EasyMock.*;
import org.junit.After;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.BeansException;
import static test.util.TestResourceUtils.*;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.Resource;
import org.springframework.util.SerializationTestUtils;
/**
* Unit tests for {@link ObjectFactoryCreatingFactoryBean}.
*
* @author Colin Sampaleanu
* @author Juergen Hoeller
* @author Rick Evans
* @author Chris Beams
* @since 2004-05-11
*/
public final class ObjectFactoryCreatingFactoryBeanTests {
public class ObjectFactoryCreatingFactoryBeanTests {
private static final Resource CONTEXT =
qualifiedResource(ObjectFactoryCreatingFactoryBeanTests.class, "context.xml");
private BeanFactory beanFactory;
private XmlBeanFactory beanFactory;
@Before
public void setUp() {
this.beanFactory = new XmlBeanFactory(CONTEXT);
this.beanFactory.setSerializationId("test");
}
@After
public void tearDown() {
this.beanFactory.setSerializationId(null);
}
@Test
public void testBasicOperation() throws BeansException {
TestBean testBean = (TestBean) beanFactory.getBean("testBean");
public void testFactoryOperation() throws Exception {
FactoryTestBean testBean = beanFactory.getBean("factoryTestBean", FactoryTestBean.class);
ObjectFactory<?> objectFactory = testBean.getObjectFactory();
Date date1 = (Date) objectFactory.getObject();
@@ -60,6 +66,40 @@ public final class ObjectFactoryCreatingFactoryBeanTests {
assertTrue(date1 != date2);
}
@Test
public void testFactorySerialization() throws Exception {
FactoryTestBean testBean = beanFactory.getBean("factoryTestBean", FactoryTestBean.class);
ObjectFactory<?> objectFactory = testBean.getObjectFactory();
objectFactory = (ObjectFactory) SerializationTestUtils.serializeAndDeserialize(objectFactory);
Date date1 = (Date) objectFactory.getObject();
Date date2 = (Date) objectFactory.getObject();
assertTrue(date1 != date2);
}
@Test
public void testProviderOperation() throws Exception {
ProviderTestBean testBean = beanFactory.getBean("providerTestBean", ProviderTestBean.class);
Provider<?> provider = testBean.getProvider();
Date date1 = (Date) provider.get();
Date date2 = (Date) provider.get();
assertTrue(date1 != date2);
}
@Test
public void testProviderSerialization() throws Exception {
ProviderTestBean testBean = beanFactory.getBean("providerTestBean", ProviderTestBean.class);
Provider<?> provider = testBean.getProvider();
provider = (Provider) SerializationTestUtils.serializeAndDeserialize(provider);
Date date1 = (Date) provider.get();
Date date2 = (Date) provider.get();
assertTrue(date1 != date2);
}
@Test
public void testDoesNotComplainWhenTargetBeanNameRefersToSingleton() throws Exception {
final String targetBeanName = "singleton";
@@ -78,7 +118,6 @@ public final class ObjectFactoryCreatingFactoryBeanTests {
assertSame(expectedSingleton, actualSingleton);
verify(beanFactory);
}
@Test
@@ -119,10 +158,9 @@ public final class ObjectFactoryCreatingFactoryBeanTests {
}
public static class TestBean {
public ObjectFactory<?> objectFactory;
public static class FactoryTestBean {
private ObjectFactory<?> objectFactory;
public ObjectFactory<?> getObjectFactory() {
return objectFactory;
@@ -131,7 +169,20 @@ public final class ObjectFactoryCreatingFactoryBeanTests {
public void setObjectFactory(ObjectFactory<?> objectFactory) {
this.objectFactory = objectFactory;
}
}
public static class ProviderTestBean {
private Provider<?> provider;
public Provider<?> getProvider() {
return provider;
}
public void setProvider(Provider<?> provider) {
this.provider = provider;
}
}
}
+2 -2
View File
@@ -8,8 +8,8 @@ Import-Template:
javax.xml.*;version="0";resolution:=optional,
net.sf.cglib.*;version="[2.1.3, 3.0.0)";resolution:=optional,
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
org.springframework.core.*;version="[3.0.0, 3.0.1)",
org.springframework.util.*;version="[3.0.0, 3.0.1)",
org.springframework.core.*;version=${spring.osgi.range},
org.springframework.util.*;version=${spring.osgi.range},
org.xml.sax.*;version="0";resolution:=optional,
org.w3c.dom.*;version="0";resolution:=optional
Ignored-Existing-Headers:
+2 -2
View File
@@ -4,12 +4,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<packaging>jar</packaging>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
</parent>
@@ -10,19 +10,19 @@ Import-Template:
javax.naming.*;version="0";resolution:=optional,
javax.sql.*;version="0";resolution:=optional,
net.sf.ehcache.*;version="[1.3.0, 2.0.0)";resolution:=optional,
net.sf.jasperreports.*;version="[2.0.5, 3.0.0)";resolution:=optional,
net.sf.jasperreports.*;version="[2.0.5, 4.0.0)";resolution:=optional,
org.apache.commons.collections.*;version="[3.2.0, 4.0.0)";resolution:=optional,
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)";resolution:=optional,
org.apache.velocity.*;version="[1.5.0, 2.0.0)";resolution:=optional,
org.quartz.*;version="[1.6.0, 2.0.0)";resolution:=optional,
org.springframework.beans.*;version="[3.0.0, 3.0.1)";resolution:=optional,
org.springframework.context.*;version="[3.0.0, 3.0.1)",
org.springframework.core.*;version="[3.0.0, 3.0.1)",
org.springframework.jdbc.*;version="[3.0.0, 3.0.1)";resolution:=optional,
org.springframework.jndi.*;version="[3.0.0, 3.0.1)";resolution:=optional,
org.springframework.scheduling.*;version="[3.0.0, 3.0.1)";resolution:=optional,
org.springframework.transaction.*;version="[3.0.0, 3.0.1)";resolution:=optional,
org.springframework.util.*;version="[3.0.0, 3.0.1)"
org.springframework.beans.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.context.*;version=${spring.osgi.range},
org.springframework.core.*;version=${spring.osgi.range},
org.springframework.jdbc.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.jndi.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.scheduling.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.transaction.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.util.*;version=${spring.osgi.range}
Ignored-Existing-Headers:
Bnd-LastModified,
Import-Package,
+38 -41
View File
@@ -1,41 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.aop"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.beans"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.core"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.expression"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.instrument"/>
<classpathentry kind="lib" path="/org.springframework.asm/target/artifacts/org.springframework.asm.jar" sourcepath="/org.springframework.asm/target/artifacts/org.springframework.asm-sources.jar"/>
<classpathentry kind="var" path="IVY_CACHE/edu.emory.mathcs.backport/com.springsource.edu.emory.mathcs.backport/3.0.0/com.springsource.edu.emory.mathcs.backport-3.0.0.jar" sourcepath="/IVY_CACHE/edu.emory.mathcs.backport/com.springsource.edu.emory.mathcs.backport/3.0.0/com.springsource.edu.emory.mathcs.backport-sources-3.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.ejb/com.springsource.javax.ejb/3.0.0/com.springsource.javax.ejb-3.0.0.jar" sourcepath="/IVY_CACHE/javax.ejb/com.springsource.javax.ejb/3.0.0/com.springsource.javax.ejb-sources-3.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.inject/com.springsource.javax.inject/1.0.0/com.springsource.javax.inject-1.0.0.jar" sourcepath="/IVY_CACHE/javax.inject/com.springsource.javax.inject/1.0.0/com.springsource.javax.inject-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.jms/com.springsource.javax.jms/1.1.0/com.springsource.javax.jms-1.1.0.jar" sourcepath="/IVY_CACHE/javax.jms/com.springsource.javax.jms/1.1.0/com.springsource.javax.jms-sources-1.1.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.persistence/com.springsource.javax.persistence/1.0.0/com.springsource.javax.persistence-1.0.0.jar" sourcepath="/IVY_CACHE/javax.persistence/com.springsource.javax.persistence/1.0.0/com.springsource.javax.persistence-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.transaction/com.springsource.javax.transaction/1.1.0/com.springsource.javax.transaction-1.1.0.jar" sourcepath="/IVY_CACHE/javax.transaction/com.springsource.javax.transaction/1.1.0/com.springsource.javax.transaction-sources-1.1.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.validation/com.springsource.javax.validation/1.0.0.GA/com.springsource.javax.validation-1.0.0.GA.jar" sourcepath="/IVY_CACHE/javax.validation/com.springsource.javax.validation/1.0.0/com.springsource.javax.validation-sources-1.0.0.GA.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.xml.rpc/com.springsource.javax.xml.rpc/1.1.0/com.springsource.javax.xml.rpc-1.1.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.2.0/com.springsource.net.sf.cglib-2.2.0.jar" sourcepath="/IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.1.3/com.springsource.net.sf.cglib-sources-2.1.3.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-1.0.0.jar" sourcepath="/IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.dbcp/1.2.2.osgi/com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.dbcp/1.2.2.osgi/com.springsource.org.apache.commons.dbcp-sources-1.2.2.osgi.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.4.0/com.springsource.org.apache.commons.pool-1.4.0.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.4.0/com.springsource.org.apache.commons.pool-sources-1.4.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-1.2.15.jar" sourcepath="/IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-sources-1.2.15.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.beanshell/com.springsource.bsh/2.0.0.b4/com.springsource.bsh-2.0.0.b4.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.codehaus.groovy/com.springsource.org.codehaus.groovy/1.6.5/com.springsource.org.codehaus.groovy-1.6.5.jar" sourcepath="/IVY_CACHE/org.codehaus.groovy/com.springsource.org.codehaus.groovy/1.6.5/com.springsource.org.codehaus.groovy-sources-1.6.5.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-2.5.1.jar" sourcepath="/IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-sources-2.5.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.objectweb.asm/com.springsource.org.objectweb.asm/3.1.0/com.springsource.org.objectweb.asm-3.1.0.jar" sourcepath="IVY_CACHE/org.objectweb.asm/com.springsource.org.objectweb.asm/3.1.0/com.springsource.org.objectweb.asm-sources-3.1.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.objectweb.asm/com.springsource.org.objectweb.asm.commons/3.1.0/com.springsource.org.objectweb.asm.commons-3.1.0.jar" sourcepath="IVY_CACHE/org.objectweb.asm/com.springsource.org.objectweb.asm.commons/3.1.0/com.springsource.org.objectweb.asm.commons-sources-3.1.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.hibernate/com.springsource.org.hibernate.validator/4.0.0.GA/com.springsource.org.hibernate.validator-4.0.0.GA.jar" sourcepath="/IVY_CACHE/org.hibernate/com.springsource.org.hibernate.validator/4.0.0.GA/com.springsource.org.hibernate.validator-sources-4.0.0.GA.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.joda/com.springsource.org.joda.time/1.6.0/com.springsource.org.joda.time-1.6.0.jar" sourcepath="/IVY_CACHE/org.joda/com.springsource.org.joda.time/1.6.0/com.springsource.org.joda.time-sources-1.6.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.jruby/com.springsource.org.jruby/1.4.0/com.springsource.org.jruby-1.4.0.jar" sourcepath="/IVY_CACHE/org.jruby/com.springsource.org.jruby/1.4.0/com.springsource.org.jruby-sources-1.4.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.7.0/com.springsource.org.junit-4.7.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.7.0/com.springsource.org.junit-sources-4.7.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.inject/com.springsource.org.atinject.tck/1.0.0/com.springsource.org.atinject.tck-1.0.0.jar" sourcepath="/IVY_CACHE/javax.inject/com.springsource.org.atinject.tck/1.0.0/com.springsource.org.atinject.tck-sources-1.0.0.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.aop"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.beans"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.core"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.expression"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.instrument"/>
<classpathentry kind="lib" path="/org.springframework.asm/target/artifacts/org.springframework.asm.jar" sourcepath="/org.springframework.asm/target/artifacts/org.springframework.asm-sources.jar"/>
<classpathentry kind="var" path="IVY_CACHE/edu.emory.mathcs.backport/com.springsource.edu.emory.mathcs.backport/3.0.0/com.springsource.edu.emory.mathcs.backport-3.0.0.jar" sourcepath="/IVY_CACHE/edu.emory.mathcs.backport/com.springsource.edu.emory.mathcs.backport/3.0.0/com.springsource.edu.emory.mathcs.backport-sources-3.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.ejb/com.springsource.javax.ejb/3.0.0/com.springsource.javax.ejb-3.0.0.jar" sourcepath="/IVY_CACHE/javax.ejb/com.springsource.javax.ejb/3.0.0/com.springsource.javax.ejb-sources-3.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.inject/com.springsource.javax.inject/1.0.0/com.springsource.javax.inject-1.0.0.jar" sourcepath="/IVY_CACHE/javax.inject/com.springsource.javax.inject/1.0.0/com.springsource.javax.inject-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.jms/com.springsource.javax.jms/1.1.0/com.springsource.javax.jms-1.1.0.jar" sourcepath="/IVY_CACHE/javax.jms/com.springsource.javax.jms/1.1.0/com.springsource.javax.jms-sources-1.1.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.persistence/com.springsource.javax.persistence/1.0.0/com.springsource.javax.persistence-1.0.0.jar" sourcepath="/IVY_CACHE/javax.persistence/com.springsource.javax.persistence/1.0.0/com.springsource.javax.persistence-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.transaction/com.springsource.javax.transaction/1.1.0/com.springsource.javax.transaction-1.1.0.jar" sourcepath="/IVY_CACHE/javax.transaction/com.springsource.javax.transaction/1.1.0/com.springsource.javax.transaction-sources-1.1.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.validation/com.springsource.javax.validation/1.0.0.GA/com.springsource.javax.validation-1.0.0.GA.jar" sourcepath="/IVY_CACHE/javax.validation/com.springsource.javax.validation/1.0.0/com.springsource.javax.validation-sources-1.0.0.GA.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.xml.rpc/com.springsource.javax.xml.rpc/1.1.0/com.springsource.javax.xml.rpc-1.1.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.2.0/com.springsource.net.sf.cglib-2.2.0.jar" sourcepath="/IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.1.3/com.springsource.net.sf.cglib-sources-2.1.3.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-1.0.0.jar" sourcepath="/IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.dbcp/1.2.2.osgi/com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.dbcp/1.2.2.osgi/com.springsource.org.apache.commons.dbcp-sources-1.2.2.osgi.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.5.3/com.springsource.org.apache.commons.pool-1.5.3.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.5.3/com.springsource.org.apache.commons.pool-sources-1.5.3.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-1.2.15.jar" sourcepath="/IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-sources-1.2.15.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.beanshell/com.springsource.bsh/2.0.0.b4/com.springsource.bsh-2.0.0.b4.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.codehaus.groovy/com.springsource.org.codehaus.groovy/1.6.5/com.springsource.org.codehaus.groovy-1.6.5.jar" sourcepath="/IVY_CACHE/org.codehaus.groovy/com.springsource.org.codehaus.groovy/1.6.5/com.springsource.org.codehaus.groovy-sources-1.6.5.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-2.5.1.jar" sourcepath="/IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-sources-2.5.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.joda/com.springsource.org.joda.time/1.6.0/com.springsource.org.joda.time-1.6.0.jar" sourcepath="/IVY_CACHE/org.joda/com.springsource.org.joda.time/1.6.0/com.springsource.org.joda.time-sources-1.6.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.jruby/com.springsource.org.jruby/1.4.0/com.springsource.org.jruby-1.4.0.jar" sourcepath="/IVY_CACHE/org.jruby/com.springsource.org.jruby/1.4.0/com.springsource.org.jruby-sources-1.4.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.7.0/com.springsource.org.junit-4.7.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.7.0/com.springsource.org.junit-sources-4.7.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.inject/com.springsource.org.atinject.tck/1.0.0/com.springsource.org.atinject.tck-1.0.0.jar" sourcepath="/IVY_CACHE/javax.inject/com.springsource.org.atinject.tck/1.0.0/com.springsource.org.atinject.tck-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.hibernate/com.springsource.org.hibernate.validator/4.0.2.GA/com.springsource.org.hibernate.validator-4.0.2.GA.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
+1 -1
View File
@@ -62,7 +62,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.hibernate" name="com.springsource.org.hibernate.validator" rev="4.0.0.GA" conf="test->runtime"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.validator" rev="4.0.2.GA" conf="test->runtime"/>
<dependency org="org.junit" name="com.springsource.org.junit" rev="${org.junit.version}" conf="test->runtime"/>
<dependency org="org.slf4j" name="com.springsource.slf4j.jcl" rev="${slf4j.version}" conf="test->runtime"/>
</dependencies>
+3 -3
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<packaging>jar</packaging>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
</parent>
<dependencies>
@@ -191,7 +191,7 @@
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.0.0.GA</version>
<version>4.0.2.GA</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -856,7 +856,8 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)) {
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
@@ -237,7 +237,7 @@ public abstract class JmxUtils {
* @return the bean class to expose
* @see org.springframework.util.ClassUtils#getUserClass(Object)
*/
public static Class getClassToExpose(Object managedBean) {
public static Class<?> getClassToExpose(Object managedBean) {
return ClassUtils.getUserClass(managedBean);
}
@@ -247,12 +247,12 @@ public abstract class JmxUtils {
* (for example, checked for annotations).
* <p>This implementation returns the superclass for a CGLIB proxy and
* the class of the given bean else (for a JDK proxy or a plain bean class).
* @param beanClass the bean class (might be an AOP proxy class)
* @param clazz the bean class (might be an AOP proxy class)
* @return the bean class to expose
* @see org.springframework.util.ClassUtils#getUserClass(Class)
*/
public static Class getClassToExpose(Class beanClass) {
return ClassUtils.getUserClass(beanClass);
public static Class<?> getClassToExpose(Class<?> clazz) {
return ClassUtils.getUserClass(clazz);
}
/**
@@ -260,14 +260,14 @@ public abstract class JmxUtils {
* <p>This implementation checks for {@link javax.management.DynamicMBean}
* classes as well as classes with corresponding "*MBean" interface
* (Standard MBeans) or corresponding "*MXBean" interface (Java 6 MXBeans).
* @param beanClass the bean class to analyze
* @param clazz the bean class to analyze
* @return whether the class qualifies as an MBean
* @see org.springframework.jmx.export.MBeanExporter#isMBean(Class)
*/
public static boolean isMBean(Class beanClass) {
return (beanClass != null &&
(DynamicMBean.class.isAssignableFrom(beanClass) ||
(getMBeanInterface(beanClass) != null || getMXBeanInterface(beanClass) != null)));
public static boolean isMBean(Class<?> clazz) {
return (clazz != null &&
(DynamicMBean.class.isAssignableFrom(clazz) ||
(getMBeanInterface(clazz) != null || getMXBeanInterface(clazz) != null)));
}
/**
@@ -277,13 +277,13 @@ public abstract class JmxUtils {
* @param clazz the class to check
* @return the Standard MBean interface for the given class
*/
public static Class getMBeanInterface(Class clazz) {
if (clazz.getSuperclass() == null) {
public static Class<?> getMBeanInterface(Class<?> clazz) {
if (clazz == null || clazz.getSuperclass() == null) {
return null;
}
String mbeanInterfaceName = clazz.getName() + MBEAN_SUFFIX;
Class[] implementedInterfaces = clazz.getInterfaces();
for (Class iface : implementedInterfaces) {
for (Class<?> iface : implementedInterfaces) {
if (iface.getName().equals(mbeanInterfaceName)) {
return iface;
}
@@ -298,12 +298,12 @@ public abstract class JmxUtils {
* @param clazz the class to check
* @return whether there is an MXBean interface for the given class
*/
public static Class getMXBeanInterface(Class clazz) {
if (clazz.getSuperclass() == null) {
public static Class<?> getMXBeanInterface(Class<?> clazz) {
if (clazz == null || clazz.getSuperclass() == null) {
return null;
}
Class[] implementedInterfaces = clazz.getInterfaces();
for (Class iface : implementedInterfaces) {
for (Class<?> iface : implementedInterfaces) {
boolean isMxBean = iface.getName().endsWith(MXBEAN_SUFFIX);
if (mxBeanAnnotationAvailable) {
Boolean checkResult = MXBeanChecker.evaluateMXBeanAnnotation(iface);
@@ -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.
@@ -17,13 +17,13 @@
package org.springframework.scheduling.annotation;
import java.lang.annotation.Annotation;
import java.util.concurrent.Executor;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.aop.framework.ProxyConfig;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
@@ -32,8 +32,6 @@ import org.springframework.core.task.TaskExecutor;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import java.util.concurrent.Executor;
/**
* Bean post-processor that automatically applies asynchronous invocation
* behavior to any bean that carries the {@link Async} annotation at class or
@@ -105,22 +103,16 @@ public class AsyncAnnotationBeanPostProcessor extends ProxyConfig
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof AopInfrastructureBean) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
Class<?> targetClass = AopUtils.getTargetClass(bean);
if (targetClass == null) {
// Can't do much here.
return bean;
}
if (AopUtils.canApply(this.asyncAnnotationAdvisor, targetClass)) {
if (bean instanceof Advised) {
((Advised) bean).addAdvisor(this.asyncAnnotationAdvisor);
@@ -26,7 +26,7 @@ import java.lang.annotation.Target;
* Annotation that marks a method to be scheduled. Exactly one of the
* <code>cron</code>, <code>fixedDelay</code>, or <code>fixedRate</code>
* attributes must be provided.
*
*
* <p>The annotated method must expect no arguments and have a
* <code>void</code> return type.
*
@@ -45,7 +45,6 @@ public @interface Scheduled {
* triggers on the second as well as minute, hour, day of month, month
* and day of week. e.g. <code>"0 * * * * MON-FRI"</code> means once
* per minute on weekdays (at the top of the minute - the 0th second).
*
* @return an expression that can be parsed to a cron schedule
*/
String cron() default "";
@@ -53,14 +52,12 @@ public @interface Scheduled {
/**
* Execute the annotated method with a fixed period between the end
* of the last invocation and the start of the next.
*
* @return the delay in milliseconds
*/
long fixedDelay() default -1;
/**
* Execute the annotated method with a fixed period between invocations.
*
* @return the period in milliseconds
*/
long fixedRate() default -1;
@@ -21,7 +21,6 @@ import java.util.HashMap;
import java.util.Map;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
@@ -82,15 +81,12 @@ public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor,
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
public Object postProcessAfterInitialization(final Object bean, String beanName) {
Class<?> targetClass = AopUtils.getTargetClass(bean);
if (targetClass == null) {
return bean;
}
ReflectionUtils.doWithMethods(targetClass, new MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Scheduled annotation = AnnotationUtils.getAnnotation(method, Scheduled.class);
@@ -20,6 +20,7 @@ import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.JdkVersion;
@@ -33,7 +34,7 @@ import org.springframework.util.StringUtils;
* @author Mark Fisher
* @since 3.0
*/
public class TaskExecutorFactoryBean implements FactoryBean<TaskExecutor>, BeanNameAware {
public class TaskExecutorFactoryBean implements FactoryBean<TaskExecutor>, BeanNameAware, DisposableBean {
private volatile TaskExecutor target;
@@ -89,6 +90,12 @@ public class TaskExecutorFactoryBean implements FactoryBean<TaskExecutor>, BeanN
public boolean isSingleton() {
return true;
}
public void destroy() throws Exception {
if (this.target instanceof DisposableBean) {
((DisposableBean) this.target).destroy();
}
}
private void initializeExecutor() throws Exception {
synchronized (this.initializationMonitor) {
@@ -50,7 +50,7 @@ import org.springframework.util.StringUtils;
* @since 3.0
* @see CronTrigger
*/
class CronSequenceGenerator {
public class CronSequenceGenerator {
private final BitSet seconds = new BitSet(60);
@@ -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.
@@ -130,9 +130,9 @@ public abstract class AbstractBindingResult extends AbstractErrors implements Bi
}
public String[] resolveMessageCodes(String errorCode, String field) {
String fixedField = fixedField(field);
Class fieldType = getFieldType(fixedField);
return getMessageCodesResolver().resolveMessageCodes(errorCode, getObjectName(), fixedField, fieldType);
Class fieldType = getFieldType(field);
return getMessageCodesResolver().resolveMessageCodes(
errorCode, getObjectName(), fixedField(field), fieldType);
}
@@ -495,7 +495,11 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
* property values, as an alternative to JavaBeans PropertyEditors.
*/
public void setConversionService(ConversionService conversionService) {
Assert.state(this.conversionService == null, "DataBinder is already initialized with ConversionService");
this.conversionService = conversionService;
if (this.bindingResult != null && conversionService != null) {
this.bindingResult.initConversion(conversionService);
}
}
/**
@@ -5,7 +5,8 @@
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
http://www.springframework.org/schema/beans/test http://www.springframework.org/schema/beans/factory/xml/support/CustomNamespaceHandlerTests.xsd">
http://www.springframework.org/schema/beans/test http://www.springframework.org/schema/beans/factory/xml/support/CustomNamespaceHandlerTests.xsd"
default-lazy-init="true">
<test:testBean id="testBean" name="Rob Harrop" age="23"/>
@@ -19,6 +20,10 @@
<property name="age" value="23"/>
</bean>
<bean id="debuggingTestBeanNoInstance" class="org.springframework.context.ApplicationListener">
<test:debug/>
</bean>
<bean id="chainedTestBean" class="org.springframework.beans.TestBean">
<test:debug/>
<test:nop/>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 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,24 +16,32 @@
package org.springframework.beans.factory.xml.support;
import static java.lang.String.format;
import static org.junit.Assert.*;
import java.io.IOException;
import static java.lang.String.format;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import test.interceptor.NopInterceptor;
import org.springframework.aop.Advisor;
import org.springframework.aop.config.AbstractInterceptorDrivenBeanDefinitionDecorator;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.interceptor.DebugInterceptor;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.ITestBean;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
@@ -49,14 +57,10 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.xml.PluggableSchemaResolver;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationListener;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import test.interceptor.NopInterceptor;
/**
* Unit tests for custom XML namespace handler implementations.
@@ -65,7 +69,7 @@ import test.interceptor.NopInterceptor;
* @author Rick Evans
* @author Chris Beams
*/
public final class CustomNamespaceHandlerTests {
public class CustomNamespaceHandlerTests {
private static final Class<?> CLASS = CustomNamespaceHandlerTests.class;
private static final String CLASSNAME = CLASS.getSimpleName();
@@ -75,46 +79,60 @@ public final class CustomNamespaceHandlerTests {
private static final String NS_XML = format("%s/%s-context.xml", FQ_PATH, CLASSNAME);
private static final String TEST_XSD = format("%s/%s.xsd", FQ_PATH, CLASSNAME);
private DefaultListableBeanFactory beanFactory;
private GenericApplicationContext beanFactory;
@Before
public void setUp() throws Exception {
NamespaceHandlerResolver resolver = new DefaultNamespaceHandlerResolver(CLASS.getClassLoader(), NS_PROPS);
this.beanFactory = new DefaultListableBeanFactory();
this.beanFactory = new GenericApplicationContext();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory);
reader.setNamespaceHandlerResolver(resolver);
reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
reader.setEntityResolver(new DummySchemaResolver());
reader.loadBeanDefinitions(getResource());
this.beanFactory.refresh();
}
@Test
public void testSimpleParser() throws Exception {
TestBean bean = (TestBean) this.beanFactory.getBean("testBean");
assetTestBean(bean);
assertTestBean(bean);
}
@Test
public void testSimpleDecorator() throws Exception {
TestBean bean = (TestBean) this.beanFactory.getBean("customisedTestBean");
assetTestBean(bean);
assertTestBean(bean);
}
@Test
public void testProxyingDecorator() throws Exception {
ITestBean bean = (ITestBean) this.beanFactory.getBean("debuggingTestBean");
assetTestBean(bean);
assertTestBean(bean);
assertTrue(AopUtils.isAopProxy(bean));
Advisor[] advisors = ((Advised) bean).getAdvisors();
assertEquals("Incorrect number of advisors", 1, advisors.length);
assertEquals("Incorrect advice class.", DebugInterceptor.class, advisors[0].getAdvice().getClass());
}
@Test
public void testProxyingDecoratorNoInstance() throws Exception {
String[] beanNames = this.beanFactory.getBeanNamesForType(ApplicationListener.class);
assertTrue(Arrays.asList(beanNames).contains("debuggingTestBeanNoInstance"));
try {
this.beanFactory.getBean("debuggingTestBeanNoInstance");
fail("Should have thrown BeanCreationException");
}
catch (BeanCreationException ex) {
assertTrue(ex.getRootCause() instanceof BeanInstantiationException);
}
}
@Test
public void testChainedDecorators() throws Exception {
ITestBean bean = (ITestBean) this.beanFactory.getBean("chainedTestBean");
assetTestBean(bean);
assertTestBean(bean);
assertTrue(AopUtils.isAopProxy(bean));
Advisor[] advisors = ((Advised) bean).getAdvisors();
assertEquals("Incorrect number of advisors", 2, advisors.length);
@@ -159,7 +177,7 @@ public final class CustomNamespaceHandlerTests {
}
private void assetTestBean(ITestBean bean) {
private void assertTestBean(ITestBean bean) {
assertEquals("Invalid name", "Rob Harrop", bean.getName());
assertEquals("Invalid age", 23, bean.getAge());
}
@@ -175,7 +193,6 @@ public final class CustomNamespaceHandlerTests {
super(CLASS.getClassLoader());
}
public InputSource resolveEntity(String publicId, String systemId) throws IOException {
InputSource source = super.resolveEntity(publicId, systemId);
if (source == null) {
@@ -27,6 +27,7 @@ import static org.junit.matchers.JUnitMatchers.*;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation6.ComponentForScanning;
import org.springframework.context.annotation6.ConfigForScanning;
import org.springframework.context.annotation6.Jsr330NamedForScanning;
@@ -154,6 +155,31 @@ public class AnnotationConfigApplicationContextTests {
assertThat(context.getBean(TestBean.class).name, equalTo("foo"));
}
@Test
public void nullReturningBeanPostProcessor() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AutowiredConfig.class);
context.getBeanFactory().addBeanPostProcessor(new BeanPostProcessor() {
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return (bean instanceof TestBean ? null : bean);
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
});
context.getBeanFactory().addBeanPostProcessor(new BeanPostProcessor() {
public Object postProcessBeforeInitialization(Object bean, String beanName) {
bean.getClass().getName();
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
bean.getClass().getName();
return bean;
}
});
context.refresh();
}
@Configuration
static class Config {
@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="foo" class="org.springframework.context.annotation.Foo">
<constructor-arg ref="barFactory"/>
<bean id="foo" class="org.springframework.context.annotation.Spr6602Tests$Foo">
<constructor-arg ref="barFactory" />
</bean>
<bean id="barFactory" class="org.springframework.context.annotation.BarFactory"/>
<bean id="barFactory" class="org.springframework.context.annotation.Spr6602Tests$BarFactory" />
</beans>
@@ -36,58 +36,67 @@ public class Spr6602Tests {
public void testXmlBehavior() throws Exception {
doAssertions(new ClassPathXmlApplicationContext("Spr6602Tests-context.xml", Spr6602Tests.class));
}
@Test
public void testConfigurationClassBehavior() throws Exception {
doAssertions(new AnnotationConfigApplicationContext(FooConfig.class));
}
private void doAssertions(ApplicationContext ctx) throws Exception {
Foo foo = ctx.getBean(Foo.class);
Bar bar1 = ctx.getBean(Bar.class);
Bar bar2 = ctx.getBean(Bar.class);
assertThat(bar1, is(bar2));
assertThat(bar1, is(foo.bar));
BarFactory barFactory1 = ctx.getBean(BarFactory.class);
BarFactory barFactory2 = ctx.getBean(BarFactory.class);
assertThat(barFactory1, is(barFactory2));
Bar bar3 = barFactory1.getObject();
Bar bar4 = barFactory1.getObject();
assertThat(bar3, is(not(bar4)));
}
}
@Configuration
public static class FooConfig {
@Bean
public Foo foo() throws Exception {
return new Foo(barFactory().getObject());
}
@Configuration
class FooConfig {
public @Bean Foo foo() throws Exception {
return new Foo(barFactory().getObject());
}
public @Bean BarFactory barFactory() {
return new BarFactory();
}
}
class Foo { final Bar bar; public Foo(Bar bar) { this.bar = bar; } }
class Bar { }
class BarFactory implements FactoryBean<Bar> {
public Bar getObject() throws Exception {
return new Bar();
@Bean
public BarFactory barFactory() {
return new BarFactory();
}
}
public Class<? extends Bar> getObjectType() {
return Bar.class;
}
public boolean isSingleton() {
return true;
public static class Foo {
final Bar bar;
public Foo(Bar bar) {
this.bar = bar;
}
}
}
public static class Bar {
}
public static class BarFactory implements FactoryBean<Bar> {
public Bar getObject() throws Exception {
return new Bar();
}
public Class<? extends Bar> getObjectType() {
return Bar.class;
}
public boolean isSingleton() {
return true;
}
}
}
@@ -249,7 +249,6 @@ public class ApplicationContextExpressionTests {
GenericApplicationContext ac = new GenericApplicationContext();
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(TestBean.class);
bd.getPropertyValues().add("country", "#{systemProperties.country}");
@@ -264,12 +263,10 @@ public class ApplicationContextExpressionTests {
public void checkPropertiesAccess() {
throw new AccessControlException("Not Allowed");
}
@Override
public void checkPermission(Permission perm) {
// allow everything else
}
};
System.setSecurityManager(securityManager);
ac.refresh();
@@ -284,6 +281,22 @@ public class ApplicationContextExpressionTests {
}
}
@Test
public void stringConcatenationWithDebugLogging() {
GenericApplicationContext ac = new GenericApplicationContext();
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(String.class);
bd.getConstructorArgumentValues().addGenericArgumentValue("test-#{ T(java.lang.System).currentTimeMillis() }");
ac.registerBeanDefinition("str", bd);
ac.refresh();
String str = ac.getBean("str", String.class);
assertTrue(str.startsWith("test-"));
}
public static class ValueTestBean implements Serializable {
@Autowired @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ")
@@ -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.
@@ -327,6 +327,83 @@ public class DataBinderTests extends TestCase {
}
}
public void testBindingErrorWithFormatter() {
TestBean tb = new TestBean();
DataBinder binder = new DataBinder(tb);
FormattingConversionService conversionService = new FormattingConversionService();
ConversionServiceFactory.addDefaultConverters(conversionService);
conversionService.addFormatterForFieldType(Float.class, new NumberFormatter());
binder.setConversionService(conversionService);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("myFloat", "1x2");
LocaleContextHolder.setLocale(Locale.GERMAN);
try {
binder.bind(pvs);
assertEquals(new Float(0.0), tb.getMyFloat());
assertEquals("1x2", binder.getBindingResult().getFieldValue("myFloat"));
assertTrue(binder.getBindingResult().hasFieldErrors("myFloat"));
}
finally {
LocaleContextHolder.resetLocaleContext();
}
}
public void testBindingWithFormatterAgainstFields() {
TestBean tb = new TestBean();
DataBinder binder = new DataBinder(tb);
FormattingConversionService conversionService = new FormattingConversionService();
ConversionServiceFactory.addDefaultConverters(conversionService);
conversionService.addFormatterForFieldType(Float.class, new NumberFormatter());
binder.setConversionService(conversionService);
binder.initDirectFieldAccess();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("myFloat", "1,2");
LocaleContextHolder.setLocale(Locale.GERMAN);
try {
binder.bind(pvs);
assertEquals(new Float(1.2), tb.getMyFloat());
assertEquals("1,2", binder.getBindingResult().getFieldValue("myFloat"));
PropertyEditor editor = binder.getBindingResult().findEditor("myFloat", Float.class);
assertNotNull(editor);
editor.setValue(new Float(1.4));
assertEquals("1,4", editor.getAsText());
editor = binder.getBindingResult().findEditor("myFloat", null);
assertNotNull(editor);
editor.setAsText("1,6");
assertEquals(new Float(1.6), editor.getValue());
}
finally {
LocaleContextHolder.resetLocaleContext();
}
}
public void testBindingErrorWithFormatterAgainstFields() {
TestBean tb = new TestBean();
DataBinder binder = new DataBinder(tb);
binder.initDirectFieldAccess();
FormattingConversionService conversionService = new FormattingConversionService();
ConversionServiceFactory.addDefaultConverters(conversionService);
conversionService.addFormatterForFieldType(Float.class, new NumberFormatter());
binder.setConversionService(conversionService);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("myFloat", "1x2");
LocaleContextHolder.setLocale(Locale.GERMAN);
try {
binder.bind(pvs);
assertEquals(new Float(0.0), tb.getMyFloat());
assertEquals("1x2", binder.getBindingResult().getFieldValue("myFloat"));
assertTrue(binder.getBindingResult().hasFieldErrors("myFloat"));
}
finally {
LocaleContextHolder.resetLocaleContext();
}
}
public void testBindingWithAllowedFields() throws Exception {
TestBean rod = new TestBean();
DataBinder binder = new DataBinder(rod);
@@ -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.
@@ -131,7 +131,7 @@ public class ValidatorFactoryTests {
@NameAddressValid
private static class ValidPerson {
public static class ValidPerson {
@NotNull
private String name;
@@ -157,7 +157,7 @@ public class ValidatorFactoryTests {
}
private static class ValidAddress {
public static class ValidAddress {
@NotNull
private String street;
+7 -7
View File
@@ -4,7 +4,7 @@ Bundle-Vendor: SpringSource
Bundle-ManifestVersion: 2
Import-Package:
javax.persistence;version="[1.0.0, 3.0.0)";resolution:=optional,
org.springframework.orm.jpa.support;version="[3.0.0, 3.0.1)";resolution:=optional,
org.springframework.orm.jpa.support;version="${spring.osgi.range.nq}";resolution:=optional,
com.ibm.websphere.management;version="0";resolution:=optional
Import-Template:
bsh.*;version="[2.0.0.b4, 3.0.0)";resolution:=optional,
@@ -25,17 +25,17 @@ Import-Template:
net.sf.cglib.*;version="[2.1.3, 3.0.0)";resolution:=optional,
org.aopalliance.*;version="[1.0.0, 2.0.0)";resolution:=optional,
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
org.aspectj.weaver.*;version="[1.5.4, 2.0.0)";resolution:=optional,
org.aspectj.weaver.*;version=${aj.osgi.range};resolution:=optional,
org.codehaus.groovy.*;version="[1.5.0, 2.0.0)";resolution:=optional,
org.joda.*;version="[1.6.0, 2.0.0)";resolution:=optional,
org.jruby.*;version="[1.1.0, 2.0.0)";resolution:=optional,
org.omg.CORBA.*;version="0";resolution:=optional,
org.springframework.aop.*;version="[3.0.0, 3.0.1)";resolution:=optional,
org.springframework.beans.*;version="[3.0.0, 3.0.1)",
org.springframework.core.*;version="[3.0.0, 3.0.1)",
org.springframework.expression.*;version="[3.0.0, 3.0.1)";resolution:=optional,
org.springframework.aop.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.beans.*;version=${spring.osgi.range},
org.springframework.core.*;version=${spring.osgi.range},
org.springframework.expression.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.instrument.*;version="0";resolution:=optional,
org.springframework.util.*;version="[3.0.0, 3.0.1)",
org.springframework.util.*;version=${spring.osgi.range},
org.xml.sax.*;version="0";resolution:=optional,
org.w3c.dom.*;version="0";resolution:=optional
Ignored-Existing-Headers:
+18 -18
View File
@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-1.2.15.jar" sourcepath="/IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-sources-1.2.15.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.7.0/com.springsource.org.junit-4.7.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.7.0/com.springsource.org.junit-sources-4.6.0.jar"/>
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-1.2.15.jar" sourcepath="/IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-sources-1.2.15.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.7.0/com.springsource.org.junit-4.7.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.7.0/com.springsource.org.junit-sources-4.6.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.servlet/com.springsource.javax.servlet/2.5.0/com.springsource.javax.servlet-2.5.0.jar" sourcepath="/IVY_CACHE/javax.servlet/com.springsource.javax.servlet/2.5.0/com.springsource.javax.servlet-sources-2.5.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.custommonkey.xmlunit/com.springsource.org.custommonkey.xmlunit/1.2.0/com.springsource.org.custommonkey.xmlunit-1.2.0.jar" sourcepath="/IVY_CACHE/org.custommonkey.xmlunit/com.springsource.org.custommonkey.xmlunit/1.2.0/com.springsource.org.custommonkey.xmlunit-sources-1.2.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-2.5.1.jar" sourcepath="/IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-sources-2.5.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.codehaus.woodstox/com.springsource.com.ctc.wstx/3.2.7/com.springsource.com.ctc.wstx-3.2.7.jar" sourcepath="/IVY_CACHE/org.codehaus.woodstox/com.springsource.com.ctc.wstx/3.2.7/com.springsource.com.ctc.wstx-sources-3.2.7.jar"/>
<classpathentry kind="lib" path="/org.springframework.asm/target/artifacts/org.springframework.asm.jar" sourcepath="/org.springframework.asm/target/artifacts/org.springframework.asm-sources.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.jboss.vfs/com.springsource.org.jboss.virtual/2.1.0.GA/com.springsource.org.jboss.virtual-2.1.0.GA.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
<classpathentry kind="var" path="IVY_CACHE/javax.servlet/com.springsource.javax.servlet/2.5.0/com.springsource.javax.servlet-2.5.0.jar" sourcepath="/IVY_CACHE/javax.servlet/com.springsource.javax.servlet/2.5.0/com.springsource.javax.servlet-sources-2.5.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.custommonkey.xmlunit/com.springsource.org.custommonkey.xmlunit/1.2.0/com.springsource.org.custommonkey.xmlunit-1.2.0.jar" sourcepath="/IVY_CACHE/org.custommonkey.xmlunit/com.springsource.org.custommonkey.xmlunit/1.2.0/com.springsource.org.custommonkey.xmlunit-sources-1.2.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-2.5.1.jar" sourcepath="/IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-sources-2.5.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.codehaus.woodstox/com.springsource.com.ctc.wstx/3.2.7/com.springsource.com.ctc.wstx-3.2.7.jar" sourcepath="/IVY_CACHE/org.codehaus.woodstox/com.springsource.com.ctc.wstx/3.2.7/com.springsource.com.ctc.wstx-sources-3.2.7.jar"/>
<classpathentry kind="lib" path="/org.springframework.asm/target/artifacts/org.springframework.asm.jar" sourcepath="/org.springframework.asm/target/artifacts/org.springframework.asm-sources.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.jboss.vfs/com.springsource.org.jboss.virtual/2.1.0.GA/com.springsource.org.jboss.virtual-2.1.0.GA.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
+2 -2
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<packaging>jar</packaging>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
</parent>
<dependencies>
@@ -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.
@@ -18,6 +18,7 @@ package org.springframework.core;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
@@ -146,14 +147,7 @@ public abstract class GenericTypeResolver {
Class[] result = new Class[typeArgs.length];
for (int i = 0; i < typeArgs.length; i++) {
Type arg = typeArgs[i];
if (arg instanceof TypeVariable) {
TypeVariable tv = (TypeVariable) arg;
arg = getTypeVariableMap(ownerClass).get(tv);
if (arg == null) {
arg = extractBoundForTypeVariable(tv);
}
}
result[i] = (arg instanceof Class ? (Class) arg : Object.class);
result[i] = extractClass(ownerClass, arg);
}
return result;
}
@@ -169,6 +163,29 @@ public abstract class GenericTypeResolver {
}
return null;
}
/**
* Extract a class instance from given Type.
*/
private static Class extractClass(Class ownerClass, Type arg) {
if (arg instanceof TypeVariable) {
TypeVariable tv = (TypeVariable) arg;
arg = getTypeVariableMap(ownerClass).get(tv);
if (arg == null) {
arg = extractBoundForTypeVariable(tv);
}
else {
arg = extractClass(ownerClass, arg);
}
}
else if (arg instanceof GenericArrayType) {
GenericArrayType gat = (GenericArrayType) arg;
Type gt = gat.getGenericComponentType();
Class<?> componentClass = extractClass(ownerClass, gt);
arg = Array.newInstance(componentClass, 0).getClass();
}
return (arg instanceof Class ? (Class) arg : Object.class);
}
/**
@@ -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.
@@ -230,7 +230,12 @@ public class MethodParameter {
if (this.parameterAnnotations == null) {
Annotation[][] annotationArray = (this.method != null ?
this.method.getParameterAnnotations() : this.constructor.getParameterAnnotations());
this.parameterAnnotations = annotationArray[this.parameterIndex];
if (this.parameterIndex >= 0 && this.parameterIndex < annotationArray.length) {
this.parameterAnnotations = annotationArray[this.parameterIndex];
}
else {
this.parameterAnnotations = new Annotation[0];
}
}
return this.parameterAnnotations;
}
@@ -103,8 +103,6 @@ public class TypeDescriptor {
this.field = field;
}
// protected constructors for subclasses
/**
* Create a new type descriptor from a method or constructor parameter.
* <p>Use this constructor when a target conversion point originates from a method parameter,
@@ -112,12 +110,23 @@ public class TypeDescriptor {
* @param methodParameter the MethodParameter to wrap
* @param type the specific type to expose (may be an array/collection element)
*/
protected TypeDescriptor(MethodParameter methodParameter, Class<?> type) {
public TypeDescriptor(MethodParameter methodParameter, Class<?> type) {
Assert.notNull(methodParameter, "MethodParameter must not be null");
this.methodParameter = methodParameter;
this.type = type;
}
/**
* Create a new type descriptor for a field.
* Use this constructor when a target conversion point originates from a field.
* @param field the field to wrap
*/
public TypeDescriptor(Field field, Class<?> type) {
Assert.notNull(field, "Field must not be null");
this.field = field;
this.type = type;
}
/**
* Internal constructor for a NULL descriptor.
*/
@@ -227,24 +236,43 @@ public class TypeDescriptor {
/**
* If this type is an array type or {@link Collection} type, returns the underlying element type.
* Returns null if the type is neither an array or collection.
* Returns <code>null</code> if the type is neither an array or collection.
*/
public Class<?> getElementType() {
return getElementTypeDescriptor().getType();
if (isArray()) {
return getArrayComponentType();
}
else if (isCollection()) {
return getCollectionElementType();
}
else {
return null;
}
}
/**
* Return the element type as a type descriptor.
*/
public TypeDescriptor getElementTypeDescriptor() {
if (isArray()) {
return TypeDescriptor.valueOf(getArrayComponentType());
return TypeDescriptor.valueOf(getElementType());
}
/**
* Create a copy of this type descriptor, preserving the context information
* but exposing the specified element type (e.g. an array/collection element).
* @param elementType the desired type to expose
* @return the type descriptor
*/
public TypeDescriptor forElementType(Class<?> elementType) {
Assert.notNull(elementType, "Element type must not be null");
if (getType().equals(elementType)) {
return this;
}
else if (isCollection()) {
return TypeDescriptor.valueOf(getCollectionElementType());
else if (this.methodParameter != null) {
return new TypeDescriptor(this.methodParameter, elementType);
}
else {
return TypeDescriptor.NULL;
return new TypeDescriptor(this.field, elementType);
}
}
@@ -345,7 +373,14 @@ public class TypeDescriptor {
return this.cachedFieldAnnotations;
}
else if (this.methodParameter != null) {
return this.methodParameter.getParameterAnnotations();
if (this.methodParameter.getParameterIndex() < 0) {
// The best we can do for return type metadata is to expose
// method-level annotations when the target is the return type...
return this.methodParameter.getMethodAnnotations();
}
else {
return this.methodParameter.getParameterAnnotations();
}
}
else {
return new Annotation[0];
@@ -28,6 +28,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConversionService;
@@ -38,7 +39,6 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.core.convert.converter.ConverterRegistry;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.style.StylerUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -122,7 +122,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
assertNotNull(sourceType, targetType);
if (logger.isDebugEnabled()) {
logger.debug("Converting value " + StylerUtils.style(source) +" of " + sourceType + " to " + targetType);
logger.debug("Converting value of " + sourceType + " to " + targetType);
}
if (sourceType == TypeDescriptor.NULL) {
Assert.isTrue(source == null, "The source must be null if sourceType == TypeDescriptor.NULL");
@@ -246,8 +246,8 @@ public class GenericConversionService implements ConversionService, ConverterReg
}
private GenericConverter findConverterForClassPair(TypeDescriptor sourceType, TypeDescriptor targetType) {
if (logger.isDebugEnabled()) {
logger.debug("Looking for Converter to convert from " + sourceType + " to " + targetType);
if (logger.isTraceEnabled()) {
logger.trace("Looking for Converter to convert from " + sourceType + " to " + targetType);
}
Class<?> sourceObjectType = sourceType.getObjectType();
if (sourceObjectType.isInterface()) {
@@ -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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.beans;
package org.springframework.core.convert.support;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
@@ -35,7 +35,7 @@ import org.springframework.util.ReflectionUtils;
* @author Juergen Hoeller
* @since 3.0
*/
class BeanTypeDescriptor extends TypeDescriptor {
public class PropertyTypeDescriptor extends TypeDescriptor {
private final PropertyDescriptor propertyDescriptor;
@@ -45,9 +45,10 @@ class BeanTypeDescriptor extends TypeDescriptor {
/**
* Create a new BeanTypeDescriptor for the given bean property.
* @param propertyDescriptor the corresponding JavaBean PropertyDescriptor
* @param methodParameter the target method parameter
*/
public BeanTypeDescriptor(PropertyDescriptor propertyDescriptor) {
super(BeanUtils.getWriteMethodParameter(propertyDescriptor));
public PropertyTypeDescriptor(PropertyDescriptor propertyDescriptor, MethodParameter methodParameter) {
super(methodParameter);
this.propertyDescriptor = propertyDescriptor;
}
@@ -57,7 +58,7 @@ class BeanTypeDescriptor extends TypeDescriptor {
* @param methodParameter the target method parameter
* @param type the specific type to expose (may be an array/collection element)
*/
public BeanTypeDescriptor(PropertyDescriptor propertyDescriptor, MethodParameter methodParameter, Class type) {
public PropertyTypeDescriptor(PropertyDescriptor propertyDescriptor, MethodParameter methodParameter, Class<?> type) {
super(methodParameter, type);
this.propertyDescriptor = propertyDescriptor;
}
@@ -70,7 +71,6 @@ class BeanTypeDescriptor extends TypeDescriptor {
return this.propertyDescriptor;
}
@Override
public Annotation[] getAnnotations() {
Annotation[] anns = this.cachedAnnotations;
if (anns == null) {
@@ -82,20 +82,22 @@ class BeanTypeDescriptor extends TypeDescriptor {
annMap.put(ann.annotationType(), ann);
}
}
Method targetMethod = getMethodParameter().getMethod();
Method writeMethod = this.propertyDescriptor.getWriteMethod();
Method readMethod = this.propertyDescriptor.getReadMethod();
if (writeMethod != null && writeMethod != targetMethod) {
if (writeMethod != null && writeMethod != getMethodParameter().getMethod()) {
for (Annotation ann : writeMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
if (readMethod != null && readMethod != targetMethod) {
if (readMethod != null && readMethod != getMethodParameter().getMethod()) {
for (Annotation ann : readMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
for (Annotation ann : targetMethod.getAnnotations()) {
for (Annotation ann : getMethodParameter().getMethodAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
for (Annotation ann : getMethodParameter().getParameterAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
anns = annMap.values().toArray(new Annotation[annMap.size()]);
@@ -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.
@@ -45,7 +45,7 @@ public class ClassPathResource extends AbstractFileResolvingResource {
private ClassLoader classLoader;
private Class clazz;
private Class<?> clazz;
/**
@@ -89,7 +89,7 @@ public class ClassPathResource extends AbstractFileResolvingResource {
* @param clazz the class to load resources with
* @see java.lang.Class#getResourceAsStream
*/
public ClassPathResource(String path, Class clazz) {
public ClassPathResource(String path, Class<?> clazz) {
Assert.notNull(path, "Path must not be null");
this.path = StringUtils.cleanPath(path);
this.clazz = clazz;
@@ -102,7 +102,7 @@ public class ClassPathResource extends AbstractFileResolvingResource {
* @param classLoader the class loader to load the resource with, if any
* @param clazz the class to load resources with, if any
*/
protected ClassPathResource(String path, ClassLoader classLoader, Class clazz) {
protected ClassPathResource(String path, ClassLoader classLoader, Class<?> clazz) {
this.path = StringUtils.cleanPath(path);
this.classLoader = classLoader;
this.clazz = clazz;
@@ -190,7 +190,16 @@ public class ClassPathResource extends AbstractFileResolvingResource {
* This implementation returns a description that includes the class path location.
*/
public String getDescription() {
return "class path resource [" + this.path + "]";
StringBuilder builder = new StringBuilder("class path resource [");
if (this.clazz != null) {
builder.append(ClassUtils.classPackageAsResourcePath(this.clazz));
builder.append('/');
}
builder.append(this.path);
builder.append(']');
return builder.toString();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 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,7 +54,7 @@ public abstract class ResourcePatternUtils {
* ResourcePatternResolver extension, or a PathMatchingResourcePatternResolver
* built on the given ResourceLoader.
* @param resourceLoader the ResourceLoader to build a pattern resolver for
* (not <code>null</code>)
* (may be <code>null</code> to indicate a default ResourceLoader)
* @return the ResourcePatternResolver
* @see PathMatchingResourcePatternResolver
*/
@@ -63,9 +63,12 @@ public abstract class ResourcePatternUtils {
if (resourceLoader instanceof ResourcePatternResolver) {
return (ResourcePatternResolver) resourceLoader;
}
else {
else if (resourceLoader != null) {
return new PathMatchingResourcePatternResolver(resourceLoader);
}
else {
return new PathMatchingResourcePatternResolver();
}
}
}
@@ -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.
@@ -19,7 +19,6 @@ package org.springframework.core.type.classreading;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
@@ -37,19 +36,9 @@ public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {
private static final int MAX_ENTRIES = 256;
@SuppressWarnings("serial")
private static final <K, V> Map<K, V> createLRUCache() {
return new LinkedHashMap<K, V>(MAX_ENTRIES, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Entry<K, V> eldest) {
return size() > MAX_ENTRIES;
}
};
}
private final Map<Resource, MetadataReader> classReaderCache = createLRUCache();
/**
* Create a new CachingMetadataReaderFactory for the default class loader.
*/
@@ -74,6 +63,7 @@ public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {
super(classLoader);
}
@Override
public MetadataReader getMetadataReader(Resource resource) throws IOException {
synchronized (this.classReaderCache) {
@@ -85,4 +75,16 @@ public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {
return metadataReader;
}
}
}
@SuppressWarnings("serial")
private static <K, V> Map<K, V> createLRUCache() {
return new LinkedHashMap<K, V>(MAX_ENTRIES, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > MAX_ENTRIES;
}
};
}
}
@@ -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.
@@ -21,12 +21,15 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import org.springframework.util.ClassUtils;
/**
* Utility to work with Java 5 generic type parameters.
* Mainly for internal use within the framework.
*
* @author Ramnivas Laddad
* @author Juergen Hoeller
* @author Chris Beams
* @since 2.0.7
*/
public abstract class TypeUtils {
@@ -38,56 +41,73 @@ public abstract class TypeUtils {
* @param rhsType the value type that should be assigned to the target type
* @return true if rhs is assignable to lhs
*/
@SuppressWarnings("unchecked")
public static boolean isAssignable(Type lhsType, Type rhsType) {
Assert.notNull(lhsType, "Left-hand side type must not be null");
Assert.notNull(rhsType, "Right-hand side type must not be null");
// all types are assignable to themselves and to class Object
if (lhsType.equals(rhsType) || lhsType.equals(Object.class)) {
return true;
}
if (lhsType instanceof Class) {
Class lhsClass = (Class) lhsType;
if (rhsType instanceof Class) {
return ClassUtils.isAssignable(lhsClass, (Class) rhsType);
if (lhsType instanceof Class<?>) {
Class<?> lhsClass = (Class<?>) lhsType;
// just comparing two classes
if (rhsType instanceof Class<?>) {
return ClassUtils.isAssignable(lhsClass, (Class<?>) rhsType);
}
else if (rhsType instanceof ParameterizedType){
if (rhsType instanceof ParameterizedType) {
Type rhsRaw = ((ParameterizedType) rhsType).getRawType();
if (rhsRaw instanceof Class) {
return ClassUtils.isAssignable(lhsClass, (Class) rhsRaw);
// a parameterized type is always assignable to its raw class type
if (rhsRaw instanceof Class<?>) {
return ClassUtils.isAssignable(lhsClass, (Class<?>) rhsRaw);
}
}
else if (lhsClass.isArray() && rhsType instanceof GenericArrayType){
else if (lhsClass.isArray() && rhsType instanceof GenericArrayType) {
Type rhsComponent = ((GenericArrayType) rhsType).getGenericComponentType();
return isAssignable(lhsClass.getComponentType(), rhsComponent);
}
}
// parameterized types are only assignable to other parameterized types and class types
if (lhsType instanceof ParameterizedType) {
if (rhsType instanceof Class) {
if (rhsType instanceof Class<?>) {
Type lhsRaw = ((ParameterizedType) lhsType).getRawType();
if (lhsRaw instanceof Class) {
return ClassUtils.isAssignable((Class) lhsRaw, (Class) rhsType);
if (lhsRaw instanceof Class<?>) {
return ClassUtils.isAssignable((Class<?>) lhsRaw, (Class<?>) rhsType);
}
}
else if (rhsType instanceof ParameterizedType) {
return isAssignable((ParameterizedType) lhsType, (ParameterizedType) rhsType);
}
}
if (lhsType instanceof GenericArrayType) {
Type lhsComponent = ((GenericArrayType) lhsType).getGenericComponentType();
if (rhsType instanceof Class) {
Class rhsClass = (Class) rhsType;
if (rhsType instanceof Class<?>) {
Class<?> rhsClass = (Class<?>) rhsType;
if (rhsClass.isArray()) {
return isAssignable(lhsComponent, rhsClass.getComponentType());
}
}
else if (rhsType instanceof GenericArrayType) {
Type rhsComponent = ((GenericArrayType) rhsType).getGenericComponentType();
return isAssignable(lhsComponent, rhsComponent);
}
}
if (lhsType instanceof WildcardType) {
return isAssignable((WildcardType) lhsType, rhsType);
}
return false;
}
@@ -95,36 +115,113 @@ public abstract class TypeUtils {
if (lhsType.equals(rhsType)) {
return true;
}
Type[] lhsTypeArguments = lhsType.getActualTypeArguments();
Type[] rhsTypeArguments = rhsType.getActualTypeArguments();
if (lhsTypeArguments.length != rhsTypeArguments.length) {
return false;
}
for (int size = lhsTypeArguments.length, i = 0; i < size; ++i) {
Type lhsArg = lhsTypeArguments[i];
Type rhsArg = rhsTypeArguments[i];
if (!lhsArg.equals(rhsArg) &&
!(lhsArg instanceof WildcardType && isAssignable((WildcardType) lhsArg, rhsArg))) {
return false;
}
}
return true;
}
private static boolean isAssignable(WildcardType lhsType, Type rhsType) {
Type[] upperBounds = lhsType.getUpperBounds();
Type[] lowerBounds = lhsType.getLowerBounds();
for (int size = upperBounds.length, i = 0; i < size; ++i) {
if (!isAssignable(upperBounds[i], rhsType)) {
return false;
Type[] lUpperBounds = lhsType.getUpperBounds();
// supply the implicit upper bound if none are specified
if (lUpperBounds.length == 0) {
lUpperBounds = new Type[] { Object.class };
}
Type[] lLowerBounds = lhsType.getLowerBounds();
// supply the implicit lower bound if none are specified
if (lLowerBounds.length == 0) {
lLowerBounds = new Type[] { null };
}
if (rhsType instanceof WildcardType) {
// both the upper and lower bounds of the right-hand side must be
// completely enclosed in the upper and lower bounds of the left-
// hand side.
WildcardType rhsWcType = (WildcardType) rhsType;
Type[] rUpperBounds = rhsWcType.getUpperBounds();
if (rUpperBounds.length == 0) {
rUpperBounds = new Type[] { Object.class };
}
Type[] rLowerBounds = rhsWcType.getLowerBounds();
if (rLowerBounds.length == 0) {
rLowerBounds = new Type[] { null };
}
for (Type lBound : lUpperBounds) {
for (Type rBound : rUpperBounds) {
if (!isAssignableBound(lBound, rBound)) {
return false;
}
}
for (Type rBound : rLowerBounds) {
if (!isAssignableBound(lBound, rBound)) {
return false;
}
}
}
for (Type lBound : lLowerBounds) {
for (Type rBound : rUpperBounds) {
if (!isAssignableBound(rBound, lBound)) {
return false;
}
}
for (Type rBound : rLowerBounds) {
if (!isAssignableBound(rBound, lBound)) {
return false;
}
}
}
}
for (int size = lowerBounds.length, i = 0; i < size; ++i) {
if (!isAssignable(rhsType, lowerBounds[i])) {
return false;
else {
for (Type lBound : lUpperBounds) {
if (!isAssignableBound(lBound, rhsType)) {
return false;
}
}
for (Type lBound : lLowerBounds) {
if (!isAssignableBound(rhsType, lBound)) {
return false;
}
}
}
return true;
}
public static boolean isAssignableBound(Type lhsType, Type rhsType) {
if (rhsType == null) {
return true;
}
if (lhsType == null) {
return false;
}
return isAssignable(lhsType, rhsType);
}
}
@@ -0,0 +1,63 @@
/*
* 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.core.io;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.junit.internal.matchers.StringContains.containsString;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.junit.Test;
/**
* Unit tests cornering bug SPR-6888.
*
* @author Chris Beams
*/
public class ClassPathResourceTests {
private static final String PACKAGE_PATH = "org/springframework/core/io";
private static final String RESOURCE_NAME = "notexist.xml";
private static final String FQ_RESOURCE_PATH = PACKAGE_PATH + '/' + RESOURCE_NAME;
@Test
public void stringConstructorRaisesExceptionWithFullyQualifiedPath() {
assertExceptionContainsFullyQualifiedPath(new ClassPathResource(FQ_RESOURCE_PATH));
}
@Test
public void classLiteralConstructorRaisesExceptionWithFullyQualifiedPath() {
assertExceptionContainsFullyQualifiedPath(new ClassPathResource(RESOURCE_NAME, this.getClass()));
}
@Test
public void classLoaderConstructorRaisesExceptionWithFullyQualifiedPath() {
assertExceptionContainsFullyQualifiedPath(new ClassPathResource(FQ_RESOURCE_PATH, this.getClass().getClassLoader()));
}
private void assertExceptionContainsFullyQualifiedPath(ClassPathResource resource) {
try {
resource.getInputStream();
fail("FileNotFoundException expected for resource: " + resource);
} catch (IOException ex) {
assertThat(ex, instanceOf(FileNotFoundException.class));
assertThat(ex.getMessage(), containsString(FQ_RESOURCE_PATH));
}
}
}
@@ -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,26 +16,41 @@
package org.springframework.util;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* Unit tests for {@link TypeUtils}.
*
* @author Juergen Hoeller
* @author Chris Beams
*/
public class TypeUtilsTests {
public static Object object;
public static String string;
public static Integer number;
public static List<Object> objects;
public static List<String> strings;
public static List<? extends Object> openObjects;
public static List<String> strings;
public static List<? extends Number> openNumbers;
public static List<? super Object> storableObjectList;
public static List<Number>[] array;
@@ -76,6 +91,25 @@ public class TypeUtilsTests {
assertFalse(TypeUtils.isAssignable(objectsType, stringsType));
}
@Test
public void withWildcardTypes() throws Exception {
ParameterizedType openObjectsType = (ParameterizedType) getClass().getField("openObjects").getGenericType();
ParameterizedType openNumbersType = (ParameterizedType) getClass().getField("openNumbers").getGenericType();
Type storableObjectListType = getClass().getField("storableObjectList").getGenericType();
Type objectType = getClass().getField("object").getGenericType();
Type numberType = getClass().getField("number").getGenericType();
Type stringType = getClass().getField("string").getGenericType();
Type openWildcard = openObjectsType.getActualTypeArguments()[0]; // '?'
Type openNumbersWildcard = openNumbersType.getActualTypeArguments()[0]; // '? extends number'
assertTrue(TypeUtils.isAssignable(openWildcard, objectType));
assertTrue(TypeUtils.isAssignable(openNumbersWildcard, numberType));
assertFalse(TypeUtils.isAssignable(openNumbersWildcard, stringType));
assertFalse(TypeUtils.isAssignable(storableObjectListType, openObjectsType));
}
@Test
public void withGenericArrayTypes() throws Exception {
Type arrayType = getClass().getField("array").getGenericType();
+2 -2
View File
@@ -7,9 +7,9 @@ Import-Package:
Import-Template:
javax.xml.*;version="0";resolution:=optional,
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
org.springframework.asm.*;version="[3.0.0, 3.0.1)";resolution:=optional,
org.springframework.asm.*;version=${spring.osgi.range};resolution:=optional,
org.apache.log4j.*;version="[1.2.15, 2.0.0)";resolution:=optional,
org.aspectj.*;version="[1.5.4, 2.0.0)";resolution:=optional,
org.aspectj.*;version=${aj.osgi.range};resolution:=optional,
org.jboss.virtual.*;version="[2.1.0.GA, 3.0.0)";resolution:=optional,
org.xml.sax.*;version="0";resolution:=optional,
org.w3c.dom.*;version="0";resolution:=optional
+2 -2
View File
@@ -4,12 +4,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<packaging>jar</packaging>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
</parent>
<dependencies>
@@ -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.
@@ -31,8 +31,9 @@ public class TemplateParserContext implements ParserContext {
private final String expressionSuffix;
/**
* Creates a new TemplateParserContext with the default #{ prefix and } suffix.
* Create a new TemplateParserContext with the default "#{" prefix and "}" suffix.
*/
public TemplateParserContext() {
this("#{", "}");
@@ -0,0 +1,72 @@
/*
* Copyright 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.expression.spel.ast;
import java.util.ArrayList;
import java.util.List;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.spel.ExpressionState;
/**
* Utilities methods for use in the Ast classes.
*
* @author Andy Clement
* @since 3.0.2
*/
public class AstUtils {
/**
* Determines the set of property resolvers that should be used to try and access a property on the specified target
* type. The resolvers are considered to be in an ordered list, however in the returned list any that are exact
* matches for the input target type (as opposed to 'general' resolvers that could work for any type) are placed at
* the start of the list. In addition, there are specific resolvers that exactly name the class in question and
* resolvers that name a specific class but it is a supertype of the class we have. These are put at the end of the
* specific resolvers set and will be tried after exactly matching accessors but before generic accessors.
*
* @param targetType the type upon which property access is being attempted
* @return a list of resolvers that should be tried in order to access the property
*/
public static List<PropertyAccessor> getPropertyAccessorsToTry(Class<?> targetType, ExpressionState state) {
List<PropertyAccessor> specificAccessors = new ArrayList<PropertyAccessor>();
List<PropertyAccessor> generalAccessors = new ArrayList<PropertyAccessor>();
for (PropertyAccessor resolver : state.getPropertyAccessors()) {
Class<?>[] targets = resolver.getSpecificTargetClasses();
if (targets == null) { // generic resolver that says it can be used for any type
generalAccessors.add(resolver);
}
else {
if (targetType != null) {
int pos = 0;
for (Class<?> clazz : targets) {
if (clazz == targetType) { // put exact matches on the front to be tried first?
specificAccessors.add(pos++, resolver);
}
else if (clazz.isAssignableFrom(targetType)) { // put supertype matches at the end of the
// specificAccessor list
generalAccessors.add(resolver);
}
}
}
}
}
List<PropertyAccessor> resolvers = new ArrayList<PropertyAccessor>();
resolvers.addAll(specificAccessors);
resolvers.addAll(generalAccessors);
return resolvers;
}
}
@@ -21,11 +21,15 @@ import java.util.List;
import java.util.Map;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
/**
* An Indexer can index into some proceeding structure to access a particular piece of it. Supported structures are:
@@ -38,11 +42,25 @@ import org.springframework.expression.spel.SpelMessage;
// TODO support correct syntax for multidimensional [][][] and not [,,,]
public class Indexer extends SpelNodeImpl {
// These fields are used when the indexer is being used as a property read accessor. If the name and
// target type match these cached values then the cachedReadAccessor is used to read the property.
// If they do not match, the correct accessor is discovered and then cached for later use.
private String cachedReadName;
private Class<?> cachedReadTargetType;
private PropertyAccessor cachedReadAccessor;
// These fields are used when the indexer is being used as a property write accessor. If the name and
// target type match these cached values then the cachedWriteAccessor is used to write the property.
// If they do not match, the correct accessor is discovered and then cached for later use.
private String cachedWriteName;
private Class<?> cachedWriteTargetType;
private PropertyAccessor cachedWriteAccessor;
public Indexer(int pos, SpelNodeImpl expr) {
super(pos, expr);
}
@SuppressWarnings("unchecked")
@Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
TypedValue context = state.getActiveContextObject();
@@ -87,61 +105,75 @@ public class Indexer extends SpelNodeImpl {
return new TypedValue(o);
}
}
int idx = (Integer)state.convertValue(index, TypeDescriptor.valueOf(Integer.class));
if (targetObject == null) {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.CANNOT_INDEX_INTO_NULL_VALUE);
}
if (targetObject.getClass().isArray()) {
return new TypedValue(accessArrayElement(targetObject, idx),TypeDescriptor.valueOf(targetObjectTypeDescriptor.getElementType()));
} else if (targetObject instanceof Collection) {
Collection c = (Collection) targetObject;
if (idx >= c.size()) {
if (state.getConfiguration().isAutoGrowCollections()) {
// Grow the collection
Object newCollectionElement = null;
try {
int newElements = idx-c.size();
Class elementClass = targetObjectTypeDescriptor.getElementType();
if (elementClass == null) {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE);
}
while (newElements>0) {
c.add(elementClass.newInstance());
newElements--;
}
newCollectionElement = targetObjectTypeDescriptor.getElementType().newInstance();
// if the object is something that looks indexable by an integer, attempt to treat the index value as a number
if ((targetObject instanceof Collection ) || targetObject.getClass().isArray() || targetObject instanceof String) {
int idx = (Integer)state.convertValue(index, TypeDescriptor.valueOf(Integer.class));
if (targetObject.getClass().isArray()) {
return new TypedValue(accessArrayElement(targetObject, idx),TypeDescriptor.valueOf(targetObjectTypeDescriptor.getElementType()));
} else if (targetObject instanceof Collection) {
Collection c = (Collection) targetObject;
if (idx >= c.size()) {
if (!growCollection(state, targetObjectTypeDescriptor.getElementType(), idx, c)) {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx);
}
catch (Exception ex) {
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.UNABLE_TO_GROW_COLLECTION);
}
int pos = 0;
for (Object o : c) {
if (pos == idx) {
return new TypedValue(o,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getElementType()));
}
c.add(newCollectionElement);
return new TypedValue(newCollectionElement,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getElementType()));
pos++;
}
else {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx);
} else if (targetObject instanceof String) {
String ctxString = (String) targetObject;
if (idx >= ctxString.length()) {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.STRING_INDEX_OUT_OF_BOUNDS, ctxString.length(), idx);
}
return new TypedValue(String.valueOf(ctxString.charAt(idx)));
}
int pos = 0;
for (Object o : c) {
if (pos == idx) {
return new TypedValue(o,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getElementType()));
}
pos++;
}
} else if (targetObject instanceof String) {
String ctxString = (String) targetObject;
if (idx >= ctxString.length()) {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.STRING_INDEX_OUT_OF_BOUNDS, ctxString.length(), idx);
}
return new TypedValue(String.valueOf(ctxString.charAt(idx)));
}
// Try and treat the index value as a property of the context object
// TODO could call the conversion service to convert the value to a String
if (indexValue.getTypeDescriptor().getType()==String.class) {
Class<?> targetObjectRuntimeClass = getObjectClass(targetObject);
String name = (String)indexValue.getValue();
EvaluationContext eContext = state.getEvaluationContext();
try {
if (cachedReadName!=null && cachedReadName.equals(name) && cachedReadTargetType!=null && cachedReadTargetType.equals(targetObjectRuntimeClass)) {
// it is OK to use the cached accessor
return cachedReadAccessor.read(eContext, targetObject, name);
}
List<PropertyAccessor> accessorsToTry = AstUtils.getPropertyAccessorsToTry(targetObjectRuntimeClass, state);
if (accessorsToTry != null) {
for (PropertyAccessor accessor : accessorsToTry) {
if (accessor.canRead(eContext, targetObject, name)) {
if (accessor instanceof ReflectivePropertyAccessor) {
accessor = ((ReflectivePropertyAccessor)accessor).createOptimalAccessor(eContext, targetObject, name);
}
this.cachedReadAccessor = accessor;
this.cachedReadName = name;
this.cachedReadTargetType = targetObjectRuntimeClass;
return accessor.read(eContext, targetObject, name);
}
}
}
} catch (AccessException e) {
throw new SpelEvaluationException(getStartPosition(), e, SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetObjectTypeDescriptor.asString());
}
}
throw new SpelEvaluationException(getStartPosition(),SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetObjectTypeDescriptor.asString());
}
@Override
public boolean isWritable(ExpressionState expressionState) throws SpelEvaluationException {
return true;
@@ -174,24 +206,94 @@ public class Indexer extends SpelNodeImpl {
if (targetObjectTypeDescriptor.isArray()) {
int idx = (Integer)state.convertValue(index, TypeDescriptor.valueOf(Integer.class));
setArrayElement(state, contextObject.getValue(), idx, newValue, targetObjectTypeDescriptor.getElementType());
return;
}
else if (targetObjectTypeDescriptor.isCollection()) {
int idx = (Integer)state.convertValue(index, TypeDescriptor.valueOf(Integer.class));
Collection c = (Collection) targetObject;
if (idx >= c.size()) {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx);
if (!growCollection(state, targetObjectTypeDescriptor.getElementType(), idx, c)) {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx);
}
}
if (targetObject instanceof List) {
List list = (List)targetObject;
Object possiblyConvertedValue = state.convertValue(newValue,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getElementType()));
list.set(idx,possiblyConvertedValue);
return;
}
else {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, contextObject.getClass().getName());
throw new SpelEvaluationException(getStartPosition(),SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetObjectTypeDescriptor.asString());
}
} else {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, contextObject.getClass().getName());
}
// Try and treat the index value as a property of the context object
// TODO could call the conversion service to convert the value to a String
if (index.getTypeDescriptor().getType()==String.class) {
Class<?> contextObjectClass = getObjectClass(contextObject.getValue());
String name = (String)index.getValue();
EvaluationContext eContext = state.getEvaluationContext();
try {
if (cachedWriteName!=null && cachedWriteName.equals(name) && cachedWriteTargetType!=null && cachedWriteTargetType.equals(contextObjectClass)) {
// it is OK to use the cached accessor
cachedWriteAccessor.write(eContext, targetObject, name,newValue);
return;
}
List<PropertyAccessor> accessorsToTry = AstUtils.getPropertyAccessorsToTry(contextObjectClass, state);
if (accessorsToTry != null) {
for (PropertyAccessor accessor : accessorsToTry) {
if (accessor.canWrite(eContext, contextObject.getValue(), name)) {
this.cachedWriteName = name;
this.cachedWriteTargetType = contextObjectClass;
this.cachedWriteAccessor = accessor;
accessor.write(eContext, contextObject.getValue(), name, newValue);
return;
}
}
}
} catch (AccessException ae) {
throw new SpelEvaluationException(getStartPosition(), ae, SpelMessage.EXCEPTION_DURING_PROPERTY_WRITE,
name, ae.getMessage());
}
}
throw new SpelEvaluationException(getStartPosition(),SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetObjectTypeDescriptor.asString());
}
/**
* Attempt to grow the specified collection so that the specified index is valid.
*
* @param state the expression state
* @param elementType the type of the elements in the collection
* @param index the index into the collection that needs to be valid
* @param collection the collection to grow with elements
* @return true if collection growing succeeded, otherwise false
*/
@SuppressWarnings("unchecked")
private boolean growCollection(ExpressionState state, Class<?> elementType, int index,
Collection collection) {
if (state.getConfiguration().isAutoGrowCollections()) {
Object newCollectionElement = null;
try {
int newElements = index-collection.size();
if (elementType == null) {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE);
}
while (newElements>0) {
collection.add(elementType.newInstance());
newElements--;
}
newCollectionElement = elementType.newInstance();
}
catch (Exception ex) {
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.UNABLE_TO_GROW_COLLECTION);
}
collection.add(newCollectionElement);
return true;
}
return false;
}
@Override
@@ -89,17 +89,7 @@ public class MethodReference extends SpelNodeImpl {
// may or may not be a root cause. If there is a root cause it is a user created exception.
// If there is no root cause it was a reflective invocation problem.
Throwable causeOfAccessException = ae.getCause();
Throwable rootCause = (causeOfAccessException==null?null:causeOfAccessException.getCause());
if (rootCause!=null) {
// User exception was the root cause - exit now
if (rootCause instanceof RuntimeException) {
throw (RuntimeException)rootCause;
} else {
throw new SpelEvaluationException( getStartPosition(), rootCause, SpelMessage.EXCEPTION_DURING_METHOD_INVOCATION,
this.name, state.getActiveContextObject().getValue().getClass().getName(), rootCause.getMessage());
}
}
throwSimpleExceptionIfPossible(state, ae);
// at this point we know it wasn't a user problem so worth a retry if a better candidate can be found
this.cachedExecutor = null;
@@ -113,11 +103,32 @@ public class MethodReference extends SpelNodeImpl {
return executorToUse.execute(
state.getEvaluationContext(), state.getActiveContextObject().getValue(), arguments);
} catch (AccessException ae) {
// Same unwrapping exception handling as above in above catch block
throwSimpleExceptionIfPossible(state, ae);
throw new SpelEvaluationException( getStartPosition(), ae, SpelMessage.EXCEPTION_DURING_METHOD_INVOCATION,
this.name, state.getActiveContextObject().getValue().getClass().getName(), ae.getMessage());
}
}
/**
* Decode the AccessException, throwing a lightweight evaluation exception or, if the cause was a RuntimeException,
* throw the RuntimeException directly.
*/
private void throwSimpleExceptionIfPossible(ExpressionState state, AccessException ae) {
Throwable causeOfAccessException = ae.getCause();
Throwable rootCause = (causeOfAccessException==null?null:causeOfAccessException.getCause());
if (rootCause!=null) {
// User exception was the root cause - exit now
if (rootCause instanceof RuntimeException) {
throw (RuntimeException)rootCause;
} else {
throw new SpelEvaluationException( getStartPosition(), rootCause, SpelMessage.EXCEPTION_DURING_METHOD_INVOCATION,
this.name, state.getActiveContextObject().getValue().getClass().getName(), rootCause.getMessage());
}
}
}
private Class<?>[] getTypes(Object... arguments) {
Class<?>[] argumentTypes = new Class[arguments.length];
for (int i = 0; i < arguments.length; i++) {
@@ -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.
@@ -41,20 +41,31 @@ import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
*/
public class PropertyOrFieldReference extends SpelNodeImpl {
private final boolean nullSafe;
private final String name;
private volatile PropertyAccessor cachedReadAccessor;
private volatile PropertyAccessor cachedWriteAccessor;
private final boolean nullSafe;
public PropertyOrFieldReference(boolean nullSafe, String propertyOrFieldName, int pos) {
super(pos);
name = propertyOrFieldName;
this.nullSafe = nullSafe;
this.name = propertyOrFieldName;
}
public boolean isNullSafe() {
return this.nullSafe;
}
public String getName() {
return this.name;
}
@Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
TypedValue result = readProperty(state, this.name);
@@ -70,28 +81,38 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
try {
if (isWritable(state)) {
List newList = ArrayList.class.newInstance();
writeProperty(state, name, newList);
writeProperty(state, this.name, newList);
result = readProperty(state, this.name);
}
} catch (InstantiationException e) {
throw new SpelEvaluationException(getStartPosition(), e, SpelMessage.UNABLE_TO_CREATE_LIST_FOR_INDEXING);
} catch (IllegalAccessException e) {
throw new SpelEvaluationException(getStartPosition(), e, SpelMessage.UNABLE_TO_CREATE_LIST_FOR_INDEXING);
}
} else {
catch (InstantiationException ex) {
throw new SpelEvaluationException(getStartPosition(), ex,
SpelMessage.UNABLE_TO_CREATE_LIST_FOR_INDEXING);
}
catch (IllegalAccessException ex) {
throw new SpelEvaluationException(getStartPosition(), ex,
SpelMessage.UNABLE_TO_CREATE_LIST_FOR_INDEXING);
}
}
else {
try {
if (isWritable(state)) {
Map newMap = HashMap.class.newInstance();
writeProperty(state, name, newMap);
result = readProperty(state, this.name);
}
} catch (InstantiationException e) {
throw new SpelEvaluationException(getStartPosition(), e, SpelMessage.UNABLE_TO_CREATE_MAP_FOR_INDEXING);
} catch (IllegalAccessException e) {
throw new SpelEvaluationException(getStartPosition(), e, SpelMessage.UNABLE_TO_CREATE_MAP_FOR_INDEXING);
}
catch (InstantiationException ex) {
throw new SpelEvaluationException(getStartPosition(), ex,
SpelMessage.UNABLE_TO_CREATE_MAP_FOR_INDEXING);
}
catch (IllegalAccessException ex) {
throw new SpelEvaluationException(getStartPosition(), ex,
SpelMessage.UNABLE_TO_CREATE_MAP_FOR_INDEXING);
}
}
} else {
}
else {
// 'simple' object
try {
if (isWritable(state)) {
@@ -99,10 +120,14 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
writeProperty(state, name, newObject);
result = readProperty(state, this.name);
}
} catch (InstantiationException e) {
throw new SpelEvaluationException(getStartPosition(), e, SpelMessage.UNABLE_TO_DYNAMICALLY_CREATE_OBJECT,result.getTypeDescriptor().getType());
} catch (IllegalAccessException e) {
throw new SpelEvaluationException(getStartPosition(), e, SpelMessage.UNABLE_TO_DYNAMICALLY_CREATE_OBJECT,result.getTypeDescriptor().getType());
}
catch (InstantiationException ex) {
throw new SpelEvaluationException(getStartPosition(), ex,
SpelMessage.UNABLE_TO_DYNAMICALLY_CREATE_OBJECT, result.getTypeDescriptor().getType());
}
catch (IllegalAccessException ex) {
throw new SpelEvaluationException(getStartPosition(), ex,
SpelMessage.UNABLE_TO_DYNAMICALLY_CREATE_OBJECT, result.getTypeDescriptor().getType());
}
}
}
@@ -176,7 +201,8 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
}
if (contextObject.getValue() == null) {
throw new SpelEvaluationException(SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL, name);
} else {
}
else {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE, name,
FormatHelper.formatClassNameForMessage(contextObjectClass));
}
@@ -215,33 +241,34 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
return;
}
}
} catch (AccessException ae) {
}
catch (AccessException ae) {
throw new SpelEvaluationException(getStartPosition(), ae, SpelMessage.EXCEPTION_DURING_PROPERTY_WRITE,
name, ae.getMessage());
}
}
if (contextObject.getValue()==null) {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL, name);
} else {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE, name, FormatHelper
.formatClassNameForMessage(contextObjectClass));
throw new SpelEvaluationException(getStartPosition(), SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL, name);
}
else {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE, name,
FormatHelper.formatClassNameForMessage(contextObjectClass));
}
}
public boolean isWritableProperty(String name, ExpressionState state) throws SpelEvaluationException {
Object contextObject = state.getActiveContextObject().getValue();
// TypeDescriptor td = state.getActiveContextObject().getTypeDescriptor();
// TypeDescriptor td = state.getActiveContextObject().getTypeDescriptor();
EvaluationContext eContext = state.getEvaluationContext();
List<PropertyAccessor> resolversToTry = getPropertyAccessorsToTry(getObjectClass(contextObject),state);
List<PropertyAccessor> resolversToTry = getPropertyAccessorsToTry(getObjectClass(contextObject), state);
if (resolversToTry != null) {
for (PropertyAccessor pfResolver : resolversToTry) {
try {
if (pfResolver.canWrite(eContext, contextObject, name)) {
return true;
}
} catch (AccessException ae) {
}
catch (AccessException ae) {
// let others try
}
}
@@ -249,6 +276,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
return false;
}
// TODO when there is more time, remove this and use the version in AstUtils
/**
* Determines the set of property resolvers that should be used to try and access a property on the specified target
* type. The resolvers are considered to be in an ordered list, however in the returned list any that are exact
@@ -287,9 +315,5 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
resolvers.addAll(generalAccessors);
return resolvers;
}
String getName() {
return name;
}
}
@@ -336,7 +336,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
if (maybeEatMethodOrProperty(nullSafeNavigation) || maybeEatFunctionOrVar() || maybeEatProjection(nullSafeNavigation) || maybeEatSelection(nullSafeNavigation)) {
return pop();
}
raiseInternalException(t.startpos,SpelMessage.UNEXPECTED_DATA_AFTER_DOT,toString(peekToken()));
if (peekToken()==null) {
// unexpectedly ran out of data
raiseInternalException(t.startpos,SpelMessage.OOD);
} else {
raiseInternalException(t.startpos,SpelMessage.UNEXPECTED_DATA_AFTER_DOT,toString(peekToken()));
}
return null;
}
@@ -1,108 +0,0 @@
/*
* Copyright 2002-2009 the original author 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.expression.spel.support;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.util.ReflectionUtils;
/**
* {@link TypeDescriptor} extension that exposes additional annotations as
* conversion metadata: namely, annotations on other accessor methods
* (getter/setter) and on the underlying field, if found.
*
* org.springframework.beans.BeanTypeDescriptor (beans module) is very
* similar to this but depending on that would introduce a beans
* dependency from the SpEL module.
*
* @author Juergen Hoeller
* @author Andy Clement
* @since 3.0
*/
public class BeanTypeDescriptor extends TypeDescriptor {
private final PropertyDescriptor propertyDescriptor;
private Annotation[] cachedAnnotations;
/**
* Create a new BeanTypeDescriptor for the given bean property.
*
* @param propertyDescriptor
* the corresponding JavaBean PropertyDescriptor
* @param methodParameter
* the target method parameter
* @param type
* the specific type to expose (may be an array/collection
* element)
*/
public BeanTypeDescriptor(PropertyDescriptor propertyDescriptor,
MethodParameter methodParameter, Class type) {
super(methodParameter, type);
this.propertyDescriptor = propertyDescriptor;
}
/**
* Return the underlying PropertyDescriptor.
*/
public PropertyDescriptor getPropertyDescriptor() {
return this.propertyDescriptor;
}
@Override
public Annotation[] getAnnotations() {
Annotation[] anns = this.cachedAnnotations;
if (anns == null) {
Field underlyingField = ReflectionUtils.findField(
getMethodParameter().getMethod().getDeclaringClass(),
this.propertyDescriptor.getName());
Map<Class, Annotation> annMap = new LinkedHashMap<Class, Annotation>();
if (underlyingField != null) {
for (Annotation ann : underlyingField.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
Method targetMethod = getMethodParameter().getMethod();
Method writeMethod = this.propertyDescriptor.getWriteMethod();
Method readMethod = this.propertyDescriptor.getReadMethod();
if (writeMethod != null && writeMethod != targetMethod) {
for (Annotation ann : writeMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
if (readMethod != null && readMethod != targetMethod) {
for (Annotation ann : readMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
for (Annotation ann : targetMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
anns = annMap.values().toArray(new Annotation[annMap.size()]);
this.cachedAnnotations = anns;
}
return anns;
}
}
@@ -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.
@@ -28,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.PropertyTypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
@@ -80,17 +81,18 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
Method method = findGetterForProperty(name, type, target instanceof Class);
if (method != null) {
// Treat it like a property
PropertyDescriptor propertyDescriptor = null;
try {
// The readerCache will only contain gettable properties (let's not worry about setters for now)
propertyDescriptor = new PropertyDescriptor(name,method,null);
} catch (IntrospectionException ex) {
throw new AccessException("Unable to access property '" + name + "' through getter "+method, ex);
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, method, null);
TypeDescriptor typeDescriptor =
new PropertyTypeDescriptor(propertyDescriptor, new MethodParameter(method, -1));
this.readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor));
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true;
}
catch (IntrospectionException ex) {
throw new AccessException("Unable to access property '" + name + "' through getter " + method, ex);
}
TypeDescriptor typeDescriptor = new BeanTypeDescriptor(propertyDescriptor, new MethodParameter(method,-1), method.getReturnType());
this.readerCache.put(cacheKey, new InvokerPair(method,typeDescriptor));
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true;
}
else {
Field field = findField(name, type, target instanceof Class);
@@ -130,16 +132,18 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (method != null) {
// TODO remove the duplication here between canRead and read
// Treat it like a property
PropertyDescriptor propertyDescriptor = null;
try {
// The readerCache will only contain gettable properties (let's not worry about setters for now)
propertyDescriptor = new PropertyDescriptor(name,method,null);
} catch (IntrospectionException ex) {
throw new AccessException("Unable to access property '" + name + "' through getter "+method, ex);
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, method, null);
TypeDescriptor typeDescriptor =
new PropertyTypeDescriptor(propertyDescriptor, new MethodParameter(method, -1));
invoker = new InvokerPair(method, typeDescriptor);
this.readerCache.put(cacheKey, invoker);
}
catch (IntrospectionException ex) {
throw new AccessException(
"Unable to access property '" + name + "' through getter " + method, ex);
}
TypeDescriptor typeDescriptor = new BeanTypeDescriptor(propertyDescriptor, new MethodParameter(method,-1), method.getReturnType());
invoker = new InvokerPair(method,typeDescriptor);
this.readerCache.put(cacheKey, invoker);
}
}
if (method != null) {
@@ -201,7 +205,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
throw new AccessException("Unable to access property '" + name + "' through setter "+method, ex);
}
MethodParameter mp = new MethodParameter(method,0);
TypeDescriptor typeDescriptor = new BeanTypeDescriptor(propertyDescriptor,mp,mp.getParameterType());
TypeDescriptor typeDescriptor = new PropertyTypeDescriptor(propertyDescriptor, mp);
this.writerCache.put(cacheKey, method);
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true;
@@ -20,8 +20,8 @@ import java.util.List;
import java.util.Map;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.Test;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
@@ -31,6 +31,7 @@ import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeLocator;
import org.springframework.expression.spel.testresources.TestPerson;
/**
* Tests the evaluation of real expressions in a real context.
@@ -222,6 +223,20 @@ public class EvaluationTests extends ExpressionTestCase {
"org.springframework.expression.spel.testresources.Inventor");
}
@Test
public void testRogueTrailingDotCausesNPE_SPR6866() {
try {
new SpelExpressionParser().parseExpression("placeOfBirth.foo.");
Assert.fail("Should have failed to parse");
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(SpelMessage.OOD,spe.getMessageCode());
Assert.assertEquals(16,spe.getPosition());
}
}
// nested properties
@Test
public void testPropertiesNested01() {
@@ -506,6 +521,33 @@ public class EvaluationTests extends ExpressionTestCase {
public void testResolvingString() throws Exception {
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
Assert.assertEquals(String.class,stringClass);
}
}
/**
* SPR-6984: attempting to index a collection on write using an index that doesn't currently exist in the collection (address.crossStreets[0] below)
*/
@Test
public void initializingCollectionElementsOnWrite() throws Exception {
TestPerson person = new TestPerson();
EvaluationContext context = new StandardEvaluationContext(person);
SpelParserConfiguration config = new SpelParserConfiguration(true, true);
ExpressionParser parser = new SpelExpressionParser(config);
Expression expression = parser.parseExpression("name");
expression.setValue(context, "Oleg");
Assert.assertEquals("Oleg",person.getName());
expression = parser.parseExpression("address.street");
expression.setValue(context, "123 High St");
Assert.assertEquals("123 High St",person.getAddress().getStreet());
expression = parser.parseExpression("address.crossStreets[0]");
expression.setValue(context, "Blah");
Assert.assertEquals("Blah",person.getAddress().getCrossStreets().get(0));
expression = parser.parseExpression("address.crossStreets[3]");
expression.setValue(context, "Wibble");
Assert.assertEquals("Blah",person.getAddress().getCrossStreets().get(0));
Assert.assertEquals("Wibble",person.getAddress().getCrossStreets().get(3));
}
}
@@ -156,6 +156,33 @@ public class MethodInvocationTests extends ExpressionTestCase {
Assert.assertEquals(4,parser.parseExpression("counter").getValue(eContext));
}
/**
* Check on first usage (when the cachedExecutor in MethodReference is null) that the exception is not wrapped.
*/
@Test
public void testMethodThrowingException_SPR6941() {
// Test method on inventor: throwException()
// On 1 it will throw an IllegalArgumentException
// On 2 it will throw a RuntimeException
// On 3 it will exit normally
// In each case it increments the Inventor field 'counter' when invoked
SpelExpressionParser parser = new SpelExpressionParser();
Expression expr = parser.parseExpression("throwException(#bar)");
eContext.setVariable("bar",2);
try {
expr.getValue(eContext);
Assert.fail();
} catch (Exception e) {
if (e instanceof SpelEvaluationException) {
e.printStackTrace();
Assert.fail("Should not be a SpelEvaluationException");
}
// normal
}
}
@Test
public void testMethodFiltering_SPR6764() {
SpelExpressionParser parser = new SpelExpressionParser();
@@ -291,6 +291,125 @@ public class SpringEL300Tests extends ExpressionTestCase {
}
}
@Test
public void testNestedProperties_SPR6923() {
StandardEvaluationContext eContext = new StandardEvaluationContext(new Foo());
String name = null;
Expression expr = null;
expr = new SpelExpressionParser().parseRaw("resource.resource.server");
name = expr.getValue(eContext,String.class);
Assert.assertEquals("abc",name);
}
static class Foo {
public ResourceSummary resource = new ResourceSummary();
}
static class ResourceSummary {
ResourceSummary() {
this.resource = new Resource();
}
private final Resource resource;
public Resource getResource() {
return resource;
}
}
static class Resource {
public String getServer() {
return "abc";
}
}
/** Should be accessing Goo.getKey because 'bar' field evaluates to "key" */
@Test
public void testIndexingAsAPropertyAccess_SPR6968_1() {
StandardEvaluationContext eContext = new StandardEvaluationContext(new Goo());
String name = null;
Expression expr = null;
expr = new SpelExpressionParser().parseRaw("instance[bar]");
name = expr.getValue(eContext,String.class);
Assert.assertEquals("hello",name);
name = expr.getValue(eContext,String.class); // will be using the cached accessor this time
Assert.assertEquals("hello",name);
}
/** Should be accessing Goo.getKey because 'bar' variable evaluates to "key" */
@Test
public void testIndexingAsAPropertyAccess_SPR6968_2() {
StandardEvaluationContext eContext = new StandardEvaluationContext(new Goo());
eContext.setVariable("bar","key");
String name = null;
Expression expr = null;
expr = new SpelExpressionParser().parseRaw("instance[#bar]");
name = expr.getValue(eContext,String.class);
Assert.assertEquals("hello",name);
name = expr.getValue(eContext,String.class); // will be using the cached accessor this time
Assert.assertEquals("hello",name);
}
/** Should be accessing Goo.wibble field because 'bar' variable evaluates to "wibble" */
@Test
public void testIndexingAsAPropertyAccess_SPR6968_3() {
StandardEvaluationContext eContext = new StandardEvaluationContext(new Goo());
eContext.setVariable("bar","wibble");
String name = null;
Expression expr = null;
expr = new SpelExpressionParser().parseRaw("instance[#bar]");
// will access the field 'wibble' and not use a getter
name = expr.getValue(eContext,String.class);
Assert.assertEquals("wobble",name);
name = expr.getValue(eContext,String.class); // will be using the cached accessor this time
Assert.assertEquals("wobble",name);
}
/** Should be accessing (setting) Goo.wibble field because 'bar' variable evaluates to "wibble" */
@Test
public void testIndexingAsAPropertyAccess_SPR6968_4() {
Goo g = Goo.instance;
StandardEvaluationContext eContext = new StandardEvaluationContext(g);
eContext.setVariable("bar","wibble");
Expression expr = null;
expr = new SpelExpressionParser().parseRaw("instance[#bar]='world'");
// will access the field 'wibble' and not use a getter
expr.getValue(eContext,String.class);
Assert.assertEquals("world",g.wibble);
expr.getValue(eContext,String.class); // will be using the cached accessor this time
Assert.assertEquals("world",g.wibble);
}
/** Should be accessing Goo.setKey field because 'bar' variable evaluates to "key" */
@Test
public void testIndexingAsAPropertyAccess_SPR6968_5() {
Goo g = Goo.instance;
StandardEvaluationContext eContext = new StandardEvaluationContext(g);
Expression expr = null;
expr = new SpelExpressionParser().parseRaw("instance[bar]='world'");
expr.getValue(eContext,String.class);
Assert.assertEquals("world",g.value);
expr.getValue(eContext,String.class); // will be using the cached accessor this time
Assert.assertEquals("world",g.value);
}
static class Goo {
public static Goo instance = new Goo();
public String bar = "key";
public String value = null;
public String wibble = "wobble";
public String getKey() {
return "hello";
}
public void setKey(String s) {
value = s;
}
}
// ---
@@ -0,0 +1,21 @@
package org.springframework.expression.spel.testresources;
import java.util.List;
public class TestAddress{
private String street;
private List<String> crossStreets;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public List<String> getCrossStreets() {
return crossStreets;
}
public void setCrossStreets(List<String> crossStreets) {
this.crossStreets = crossStreets;
}
}
@@ -0,0 +1,19 @@
package org.springframework.expression.spel.testresources;
public class TestPerson {
private String name;
private TestAddress address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public TestAddress getAddress() {
return address;
}
public void setAddress(TestAddress address) {
this.address = address;
}
}
+2 -2
View File
@@ -4,5 +4,5 @@ Bundle-Vendor: SpringSource
Bundle-ManifestVersion: 2
Import-Template:
org.apache.commons.logging;version="[1.1.1, 2.0.0)",
org.springframework.core.*;version="[3.0.0, 3.0.1)",
org.springframework.util.*;version="[3.0.0, 3.0.1)"
org.springframework.core.*;version=${spring.osgi.range},
org.springframework.util.*;version=${spring.osgi.range}
@@ -4,12 +4,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-instrument-tomcat</artifactId>
<packaging>jar</packaging>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
</parent>
<dependencies>
+2 -2
View File
@@ -4,12 +4,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<packaging>jar</packaging>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
</parent>
</project>
@@ -4,12 +4,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-integration-tests</artifactId>
<packaging>jar</packaging>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
+2 -2
View File
@@ -4,12 +4,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<packaging>jar</packaging>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.0.1.RELEASE</version>
<version>3.0.2.RELEASE</version>
</parent>
<dependencies>
<dependency>

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