From b663c6ff8b700d2616b25f4a32d1423eade7ffb9 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Mon, 3 Nov 2008 09:56:23 +0000 Subject: [PATCH] Added Tiger tests git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@255 50f2f4bb-b051-0410-bef5-90022cba6387 --- .../BeanNamePointcutAtAspectTests.java | 117 ++ ...licitJPArgumentMatchingAtAspectJTests.java | 55 + .../aop/aspectj/JoinPointMonitorAspect.java | 53 + .../JoinPointMonitorAtAspectJAspect.java | 58 + .../aspectj/PropertyDependentAspectTests.java | 72 + ...tSelectionOnlyPointcutsAtAspectJTests.java | 195 +++ ...ctJAdviceParameterNameDiscovererTests.java | 78 + .../TigerAspectJExpressionPointcutTests.java | 261 ++++ .../AbstractAspectJAdvisorFactoryTests.java | 903 ++++++++++++ .../annotation/AbstractMakeModifiable.java | 109 ++ .../annotation/ArgumentBindingTests.java | 88 ++ ...eParameterNameDiscoverAnnotationTests.java | 46 + .../AspectJPointcutAdvisorTests.java | 84 ++ .../annotation/AspectMetadataTests.java | 65 + .../annotation/AspectProxyFactoryTests.java | 122 ++ .../aspectj/annotation/CannotBeUnlocked.java | 44 + .../aop/aspectj/annotation/FooAspect.java | 28 + .../annotation/MakeITestBeanModifiable.java | 34 + .../aop/aspectj/annotation/MakeLockable.java | 73 + .../aop/aspectj/annotation/Modifiable.java | 30 + .../annotation/NamedPointcutWithArgs.java | 39 + .../aop/aspectj/annotation/NotLockable.java | 15 + .../PointcutWithAnnotationArgument.java | 37 + .../ReflectiveAspectJAdvisorFactoryTests.java | 33 + .../autoproxy/AdviceUsingThisJoinPoint.java | 41 + .../aspectj/autoproxy/AnnotatedTestBean.java | 33 + .../autoproxy/AnnotatedTestBeanImpl.java | 48 + .../AnnotationBindingTestAspect.java | 30 + .../autoproxy/AnnotationBindingTests.java | 46 + .../autoproxy/AnnotationPointcutTests.java | 56 + ...xyCreatorAndLazyInitTargetSourceTests.java | 46 + .../AspectJAutoProxyCreatorTests.java | 319 +++++ .../AspectJNamespaceHandlerTests.java | 97 ++ .../AtAspectJAfterThrowingTests.java | 49 + .../AtAspectJAnnotationBindingTestAspect.java | 38 + .../AtAspectJAnnotationBindingTests.java | 54 + .../aop/aspectj/autoproxy/DummyAspect.java | 34 + .../autoproxy/DummyAspectWithParameter.java | 34 + .../aspectj/autoproxy/DummyFactoryBean.java | 38 + .../autoproxy/ExceptionHandlingAspect.java | 41 + .../autoproxy/IncreaseReturnValue.java | 38 + .../aop/aspectj/autoproxy/LazyTestBean.java | 36 + .../autoproxy/MultiplyReturnValue.java | 48 + .../aop/aspectj/autoproxy/PerThisAspect.java | 37 + .../autoproxy/ResourceArrayFactoryBean.java | 41 + .../aop/aspectj/autoproxy/RetryAspect.java | 83 ++ .../aspectj/autoproxy/RetryableException.java | 34 + .../aop/aspectj/autoproxy/TestAnnotation.java | 30 + .../aspectj/autoproxy/TestBeanAdvisor.java | 41 + .../aop/aspectj/autoproxy/UnreliableBean.java | 34 + .../autoproxy/afterThrowingAdviceTests.xml | 13 + .../aspectj/autoproxy/annotationPointcut.xml | 22 + .../aspectj/autoproxy/around-advice-tests.xml | 18 + .../aop/aspectj/autoproxy/aspects.xml | 39 + .../aspectj/autoproxy/aspectsPlusAdvisor.xml | 28 + .../autoproxy/aspectsWithAbstractBean.xml | 29 + .../aspectj/autoproxy/aspectsWithCGLIB.xml | 16 + .../aspectj/autoproxy/aspectsWithOrdering.xml | 25 + .../ataspectj-around-advice-tests.xml | 22 + .../autoproxy/benchmark/BenchmarkTests.java | 168 +++ .../MultiplyReturnValueInterceptor.java | 42 + .../benchmark/TraceAfterReturningAdvice.java | 51 + .../autoproxy/benchmark/TraceAspect.java | 40 + .../benchmark/TraceBeforeAdvice.java | 44 + .../aspectj/autoproxy/benchmark/aspectj.xml | 32 + .../aspectj/autoproxy/benchmark/springAop.xml | 39 + .../aop/aspectj/autoproxy/lazy.xml | 28 + .../aop/aspectj/autoproxy/pertarget.xml | 23 + .../aop/aspectj/autoproxy/perthis.xml | 15 + .../aop/aspectj/autoproxy/retryAspect.xml | 15 + .../autoproxy/spr3064/SPR3064Tests.java | 47 + .../aspectj/autoproxy/spr3064/Service.java | 26 + .../autoproxy/spr3064/ServiceImpl.java | 32 + .../autoproxy/spr3064/Transaction.java | 28 + .../spr3064/TransactionInterceptor.java | 35 + .../spr3064/annotationbinding-spr3064.xml | 14 + .../aop/aspectj/autoproxy/twoAdviceAspect.xml | 15 + .../autoproxy/twoAdviceAspectPrototype.xml | 16 + .../aop/aspectj/autoproxy/usesInclude.xml | 26 + .../aspectj/autoproxy/usesJoinPointAspect.xml | 15 + .../bean-name-pointcut-atAspect-tests.xml | 15 + ...fterReturningGenericTypeMatchingTests.java | 169 +++ ...icBridgeMethodMatchingClassProxyTests.java | 45 + .../GenericBridgeMethodMatchingTests.java | 103 ++ .../GenericParameterMatchingTests.java | 129 ++ ...urningGenericTypeMatchingTests-context.xml | 14 + ...MethodMatchingTests-classProxy-context.xml | 14 + ...nericBridgeMethodMatchingTests-context.xml | 14 + .../genericParameterMatchingTests-context.xml | 14 + ...t-jp-argument-matching-atAspectJ-tests.xml | 18 + ...dent-aspect-property-after-aspect-test.xml | 22 + ...ent-aspect-property-before-aspect-test.xml | 22 + ...ectJ-aspect-property-after-aspect-test.xml | 17 + ...ctJ-aspect-property-before-aspect-test.xml | 18 + ...electionOnly-pointcuts-atAspectJ-tests.xml | 17 + .../org/springframework/beans/CustomEnum.java | 30 + .../springframework/beans/GenericBean.java | 237 +++ .../beans/GenericIntegerBean.java | 24 + .../beans/GenericSetOfIntegerBean.java | 26 + ...AnnotationBeanWiringInfoResolverTests.java | 80 ++ ...wiredAnnotationBeanPostProcessorTests.java | 1272 +++++++++++++++++ .../CustomAutowireConfigurerTests.java | 81 ++ .../beans/factory/annotation/MyRequired.java | 32 + ...uiredAnnotationBeanPostProcessorTests.java | 80 ++ .../factory/annotation/RequiredTestBean.java | 82 ++ .../annotation/customAutowireConfigurer.xml | 33 + ...uiredWithAllRequiredPropertiesProvided.xml | 14 + .../requiredWithCustomAnnotation.xml | 12 + ...requiredWithOneRequiredPropertyOmitted.xml | 14 + ...iredWithThreeRequiredPropertiesOmitted.xml | 12 + .../MethodInvokingFactoryBeanTests.java | 339 ----- .../GenericBeanFactoryAccessorTests.java | 78 + .../beans/factory/generic/MyAnnotation.java | 32 + .../factory/generic/SomeAnnotatedBean.java | 26 + .../genericBeanFactoryAccessorTests.xml | 10 + .../serviceloader/ServiceLoaderTests.java | 76 + .../support/BeanFactoryGenericsTests.java | 595 ++++++++ ...ierAnnotationAutowireBeanFactoryTests.java | 234 +++ ...alifierAnnotationAutowireContextTests.java | 683 +++++++++ .../factory/support/genericBeanTests.xml | 70 + .../factory/xml/QualifierAnnotationTests.java | 287 ++++ .../factory/xml/qualifierAnnotationTests.xml | 44 + .../AnnotationBeanNameGeneratorTests.java | 115 ++ .../AnnotationProcessorPerformanceTests.java | 163 +++ .../AnnotationScopeMetadataResolverTests.java | 69 + .../AutowiredQualifierFooService.java | 51 + ...ssPathBeanDefinitionScannerScopeTests.java | 331 +++++ .../ClassPathBeanDefinitionScannerTests.java | 411 ++++++ ...anningCandidateComponentProviderTests.java | 149 ++ ...ommonAnnotationBeanPostProcessorTests.java | 470 ++++++ ...ScanParserBeanDefinitionDefaultsTests.java | 288 ++++ .../ComponentScanParserScopedProxyTests.java | 80 ++ .../annotation/ComponentScanParserTests.java | 112 ++ ...nParserWithUserDefinedStrategiesTests.java | 66 + .../context/annotation/CustomComponent.java | 33 + .../context/annotation/CustomStereotype.java | 36 + .../annotation/DefaultNamedComponent.java | 27 + .../context/annotation/DoubleScanTests.java | 29 + .../context/annotation/FooDao.java | 26 + .../context/annotation/FooService.java | 29 + .../context/annotation/FooServiceImpl.java | 80 ++ ...validConstructorTestBeanNameGenerator.java | 36 + .../context/annotation/MessageBean.java | 39 + .../context/annotation/NamedComponent.java | 27 + .../context/annotation/NamedStubDao.java | 31 + .../annotation/ScopedProxyTestBean.java | 34 + .../annotation/ServiceInvocationCounter.java | 46 + .../context/annotation/SimpleConfigTests.java | 53 + .../context/annotation/SimpleScanTests.java | 61 + .../Spr3775InitDestroyLifecycleTests.java | 261 ++++ .../context/annotation/StubFooDao.java | 33 + .../annotation/TestBeanNameGenerator.java | 32 + .../annotation/TestScopeMetadataResolver.java | 32 + .../annotation/aspectjTypeFilterTests.xml | 14 + ...mponentScanWithAutowiredQualifierTests.xml | 14 + ...dForBothComponentScanAndQualifierTests.xml | 22 + .../annotation/customNameGeneratorTests.xml | 11 + .../annotation/customScopeResolverTests.xml | 11 + .../annotation/customTypeFilterTests.xml | 22 + .../annotation/defaultAutowireByNameTests.xml | 29 + .../annotation/defaultAutowireByTypeTests.xml | 29 + .../defaultAutowireConstructorTests.xml | 29 + .../annotation/defaultAutowireNoTests.xml | 29 + .../defaultDependencyCheckAllTests.xml | 29 + ...ncyCheckObjectsWithAutowireByNameTests.xml | 27 + .../defaultInitAndDestroyMethodsTests.xml | 15 + .../annotation/defaultLazyInitFalseTests.xml | 16 + .../annotation/defaultLazyInitTrueTests.xml | 16 + ...tNonExistingInitAndDestroyMethodsTests.xml | 15 + .../defaultWithNoOverridesTests.xml | 28 + .../context/annotation/doubleScanTests.xml | 17 + .../invalidClassNameScopeResolverTests.xml | 11 + .../invalidConstructorNameGeneratorTests.xml | 11 + .../ltw/ComponentScanningWithLTWTests.java | 42 + .../ltw/ComponentScanningWithLTWTests.xml | 17 + .../matchingResourcePatternTests.xml | 15 + .../nonMatchingResourcePatternTests.xml | 15 + .../annotation/scopedProxyDefaultTests.xml | 14 + .../annotation/scopedProxyInterfacesTests.xml | 14 + .../scopedProxyInvalidConfigTests.xml | 15 + .../context/annotation/scopedProxyNoTests.xml | 14 + .../scopedProxyTargetClassTests.xml | 14 + .../context/annotation/simpleConfigTests.xml | 20 + .../context/annotation/simpleScanTests.xml | 14 + .../context/annotation2/NamedStubDao2.java | 31 + .../context/annotation3/StubFooDao.java | 34 + .../core/AbstractGenericsTests.java | 54 + .../core/BridgeMethodResolverTests.java | 1264 ++++++++++++++++ .../GenericCollectionTypeResolverTests.java | 136 ++ .../core/annotation/AnnotationUtilsTests.java | 279 ++++ .../core/type/AnnotationMetadataTests.java | 77 + .../core/type/AnnotationTypeFilterTests.java | 130 ++ .../core/type/AspectJTypeFilterTests.java | 164 +++ .../core/type/AssignableTypeFilterTests.java | 97 ++ .../core/type/ClassloadingAssertions.java | 45 + .../LocalSlsbInvokerInterceptorTests.java | 229 +++ ...StatelessSessionProxyFactoryBeanTests.java | 210 +++ ...mpleRemoteSlsbInvokerInterceptorTests.java | 416 ++++++ ...StatelessSessionProxyFactoryBeanTests.java | 321 +++++ .../config/JeeNamespaceHandlerEventTests.java | 62 + .../ejb/config/JeeNamespaceHandlerTests.java | 125 ++ .../ejb/config/jeeNamespaceHandlerTests.xml | 71 + .../ejb/support/EjbSupportTests.java | 224 +++ .../InstrumentableClassLoaderTests.java | 35 + .../ReflectiveLoadTimeWeaverTests.java | 116 ++ ...ceOverridingShadowingClassLoaderTests.java | 79 + .../GlassFishLoadTimeWeaverTests.java | 153 ++ .../OC4JClassPreprocessorAdapterTests.java | 65 + .../oc4j/OC4JLoadTimeWeaverTests.java | 45 + .../instrument/classloading/testResource.xml | 3 + .../core/simple/CallMetaDataContextTests.java | 114 ++ ...rameterizedBeanPropertyRowMapperTests.java | 73 + .../jdbc/core/simple/SimpleJdbcCallTests.java | 469 ++++++ .../core/simple/SimpleJdbcInsertTests.java | 118 ++ .../core/simple/SimpleJdbcTemplateTests.java | 677 +++++++++ .../simple/TableMetaDataContextTests.java | 241 ++++ .../AnnotationLazyInitMBeanTests.java | 90 ++ .../AnnotationMetadataAssemblerTests.java | 46 + .../export/annotation/AnnotationTestBean.java | 101 ++ .../annotation/JmxUtilsAnnotationTests.java | 77 + .../jmx/export/annotation/annotations.xml | 45 + .../jmx/export/annotation/componentScan.xml | 14 + .../jmx/export/annotation/lazyAssembling.xml | 25 + .../jmx/export/annotation/lazyNaming.xml | 17 + .../orm/ibatis/SqlMapClientTests.java | 462 ++++++ .../ibatis/support/LobTypeHandlerTests.java | 241 ++++ ...rEntityManagerFactoryIntegrationTests.java | 258 ++++ ...AbstractEntityManagerFactoryBeanTests.java | 90 ++ ...tEntityManagerFactoryIntegrationTests.java | 95 ++ ...nManagedEntityManagerIntegrationTests.java | 165 +++ ...rManagedEntityManagerIntegrationTests.java | 178 +++ .../orm/jpa/DefaultJpaDialectTests.java | 85 ++ .../EntityManagerFactoryBeanSupportTests.java | 45 + .../jpa/EntityManagerFactoryUtilsTests.java | 154 ++ .../orm/jpa/JpaInterceptorTests.java | 300 ++++ .../orm/jpa/JpaTemplateTests.java | 521 +++++++ .../orm/jpa/JpaTransactionManagerTests.java | 1074 ++++++++++++++ ...ontainerEntityManagerFactoryBeanTests.java | 397 +++++ .../LocalEntityManagerFactoryBeanTests.java | 94 ++ .../orm/jpa/META-INF/persistence.xml | 5 + .../orm/jpa/domain/ContextualPerson.java | 105 ++ .../orm/jpa/domain/DriversLicense.java | 44 + .../orm/jpa/domain/Person.java | 103 ++ .../orm/jpa/domain/persistence-context.xml | 13 + .../orm/jpa/domain/persistence-multi.xml | 17 + .../orm/jpa/domain/persistence.xml | 12 + ...kEntityManagerFactoryIntegrationTests.java | 47 + .../jpa/eclipselink/eclipselink-manager.xml | 18 + ...eEntityManagerFactoryIntegrationTests.java | 80 ++ ...iEntityManagerFactoryIntegrationTests.java | 65 + .../jpa/hibernate/hibernate-manager-multi.xml | 22 + .../orm/jpa/hibernate/hibernate-manager.xml | 41 + .../org/springframework/orm/jpa/inject.xml | 23 + .../springframework/orm/jpa/jpa-archive.jar | Bin 0 -> 403 bytes .../org/springframework/orm/jpa/memdb.xml | 32 + .../springframework/orm/jpa/multi-jpa-emf.xml | 25 + ...aEntityManagerFactoryIntegrationTests.java | 82 ++ ...oryWithAspectJWeavingIntegrationTests.java | 33 + .../openjpa-manager-aspectj-weaving.xml | 23 + .../orm/jpa/openjpa/openjpa-manager.xml | 18 + .../orm/jpa/persistence-complex.xml | 30 + .../orm/jpa/persistence-example1.xml | 8 + .../orm/jpa/persistence-example2.xml | 10 + .../orm/jpa/persistence-example3.xml | 11 + .../orm/jpa/persistence-example4.xml | 18 + .../orm/jpa/persistence-example5.xml | 14 + .../orm/jpa/persistence-example6.xml | 11 + .../orm/jpa/persistence-invalid.xml | 8 + .../orm/jpa/persistence-no-schema.xml | 3 + .../PersistenceXmlParsingTests.java | 267 ++++ .../orm/jpa/support/JpaDaoSupportTests.java | 98 ++ .../support/OpenEntityManagerInViewTests.java | 206 +++ .../PersistenceInjectionIntegrationTests.java | 63 + .../support/PersistenceInjectionTests.java | 843 +++++++++++ .../SharedEntityManagerFactoryTests.java | 89 ++ ...kEntityManagerFactoryIntegrationTests.java | 48 + ...iEntityManagerFactoryIntegrationTests.java | 65 + .../orm/jpa/toplink/toplink-manager-multi.xml | 16 + .../orm/jpa/toplink/toplink-manager.xml | 18 + .../remoting/caucho/CauchoRemotingTests.java | 224 +++ .../remoting/jaxws/JaxWsSupportTests.java | 144 ++ .../jaxws/OrderNotFoundException.java | 42 + .../remoting/jaxws/OrderService.java | 31 + .../remoting/jaxws/OrderServiceImpl.java | 42 + .../ConcurrentTaskExecutorTests.java | 47 + .../ScheduledExecutorFactoryBeanTests.java | 264 ++++ .../jruby/JRubyScriptFactoryTests.java | 35 +- ...otationAwareTransactionalTests-context.xml | 12 + ...alueAnnotationAwareTransactionalTests.java | 146 ++ .../SpringRunnerContextCacheTests.java | 118 ++ .../test/context/TestContextManagerTests.java | 177 +++ .../context/TestExecutionListenersTests.java | 145 ++ ...ionalJUnit38SpringContextTests-context.xml | 33 + ...ransactionalJUnit38SpringContextTests.java | 229 +++ ...lingBeforeAndAfterMethodsTests-context.xml | 12 + .../FailingBeforeAndAfterMethodsTests.java | 150 ++ ...ProfileValueJUnit38SpringContextTests.java | 146 ++ .../RepeatedJUnit38SpringContextTests.java | 95 ++ ...athSpringJUnit4ClassRunnerAppCtxTests.java | 38 + ...bstractTransactionalSpringRunnerTests.java | 73 + ...fterTransactionAnnotationTests-context.xml | 8 + ...oreAndAfterTransactionAnnotationTests.java | 140 ++ .../ClassLevelDisabledSpringRunnerTests.java | 57 + ...TransactionalSpringRunnerTests-context.xml | 8 + ...ssLevelTransactionalSpringRunnerTests.java | 118 ++ ...rceSpringJUnit4ClassRunnerAppCtxTests.java | 52 + ...tionalJUnit4SpringContextTests-context.xml | 29 + ...TransactionalJUnit4SpringContextTests.java | 236 +++ ...TransactionalSpringRunnerTests-context.xml | 15 + ...ckFalseTransactionalSpringRunnerTests.java | 91 ++ ...TransactionalSpringRunnerTests-context.xml | 8 + ...ackTrueTransactionalSpringRunnerTests.java | 88 ++ .../EnabledAndIgnoredSpringRunnerTests.java | 101 ++ ...lingBeforeAndAfterMethodsTests-context.xml | 12 + .../FailingBeforeAndAfterMethodsTests.java | 165 +++ ...edProfileValueSourceSpringRunnerTests.java | 56 + ...figSpringJUnit4ClassRunnerAppCtxTests.java | 35 + ...TransactionalSpringRunnerTests-context.xml | 8 + ...odLevelTransactionalSpringRunnerTests.java | 118 ++ ...gJUnit4ClassRunnerAppCtxTests-context1.xml | 11 + ...gJUnit4ClassRunnerAppCtxTests-context2.xml | 9 + ...gJUnit4ClassRunnerAppCtxTests-context3.xml | 13 + ...cesSpringJUnit4ClassRunnerAppCtxTests.java | 45 + ...erizedDependencyInjectionTests-context.xml | 21 + ...ParameterizedDependencyInjectionTests.java | 115 ++ ...4ClassRunnerAppCtxTests-context.properties | 5 + ...sedSpringJUnit4ClassRunnerAppCtxTests.java | 78 + ...athSpringJUnit4ClassRunnerAppCtxTests.java | 37 + .../RepeatedSpringMethodRoadieTests.java | 140 ++ ...TransactionalSpringRunnerTests-context.xml | 15 + ...ckFalseTransactionalSpringRunnerTests.java | 88 ++ ...TransactionalSpringRunnerTests-context.xml | 8 + ...ackTrueTransactionalSpringRunnerTests.java | 86 ++ ...ngJUnit4ClassRunnerAppCtxTests-context.xml | 23 + .../SpringJUnit4ClassRunnerAppCtxTests.java | 171 +++ .../junit4/SpringJUnit4ClassRunnerTests.java | 48 + .../junit4/SpringJUnit4SuiteTests.java | 95 ++ ...andardJUnit4FeaturesSpringRunnerTests.java | 44 + .../junit4/StandardJUnit4FeaturesTests.java | 108 ++ .../TimedTransactionalSpringRunnerTests.java | 72 + ...DefaultLocationsInheritedTests-context.xml | 11 + ...rridingDefaultLocationsInheritedTests.java | 47 + ...ridingExplicitLocationsInheritedTests.java | 47 + .../DefaultLocationsBaseTests-context.xml | 11 + .../spr3896/DefaultLocationsBaseTests.java | 58 + ...DefaultLocationsInheritedTests-context.xml | 9 + .../DefaultLocationsInheritedTests.java | 52 + .../spr3896/ExplicitLocationsBaseTests.java | 58 + .../ExplicitLocationsInheritedTests.java | 52 + .../junit4/spr3896/Spr3896SuiteTests.java | 51 + .../junit4/transactionalTests-context.xml | 15 + ...edGenericXmlContextLoaderTests-context.xml | 7 + ...ustomizedGenericXmlContextLoaderTests.java | 58 + ...mlContextLoaderResourceLocationsTests.java | 137 ++ ...tionalTestNGSpringContextTests-context.xml | 33 + ...TransactionalTestNGSpringContextTests.java | 291 ++++ ...tionalTestNGSpringContextTests-context.xml | 12 + ...TransactionalTestNGSpringContextTests.java | 84 ++ ...lingBeforeAndAfterMethodsTests-context.xml | 12 + .../FailingBeforeAndAfterMethodsTests.java | 207 +++ ...tationTransactionAttributeSourceTests.java | 508 +++++++ ...AnnotationTransactionInterceptorTests.java | 374 +++++ ...ationTransactionNamespaceHandlerTests.java | 135 ++ ...tationTransactionNamespaceHandlerTests.xml | 21 + .../config/AnnotationDrivenTests.java | 49 + .../config/TransactionalService.java | 32 + .../annotationDrivenProxyTargetClassTests.xml | 19 + .../springframework/util/TypeUtilsTests.java | 61 + .../PortletAnnotationControllerTests.java | 777 ++++++++++ .../mvc/annotation/AdminController.java | 27 + .../web/servlet/mvc/annotation/BuyForm.java | 27 + ...ontrollerClassNameHandlerMappingTests.java | 117 ++ .../mvc/annotation/IndexController.java | 37 + .../MethodNameDispatchingController.java | 54 + .../ServletAnnotationControllerTests.java | 1137 +++++++++++++++ .../mvc/annotation/WelcomeController.java | 37 + .../servlet/mvc/annotation/class-mapping.xml | 59 + .../servlet/tags/form/OptionTagEnumTests.java | 72 + 378 files changed, 36585 insertions(+), 356 deletions(-) create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutAtAspectTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ImplicitJPArgumentMatchingAtAspectJTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/JoinPointMonitorAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/JoinPointMonitorAtAspectJAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/PropertyDependentAspectTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TigerAspectJAdviceParameterNameDiscovererTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TigerAspectJExpressionPointcutTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AbstractMakeModifiable.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/ArgumentBindingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectJAdviceParameterNameDiscoverAnnotationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectJPointcutAdvisorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectMetadataTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectProxyFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/CannotBeUnlocked.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/FooAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/MakeITestBeanModifiable.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/MakeLockable.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/Modifiable.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/NamedPointcutWithArgs.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/NotLockable.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/PointcutWithAnnotationArgument.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AdviceUsingThisJoinPoint.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotatedTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotatedTestBeanImpl.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationBindingTestAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationBindingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationPointcutTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJAutoProxyCreatorAndLazyInitTargetSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJAutoProxyCreatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJNamespaceHandlerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AtAspectJAfterThrowingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AtAspectJAnnotationBindingTestAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AtAspectJAnnotationBindingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/DummyAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/DummyAspectWithParameter.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/DummyFactoryBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/ExceptionHandlingAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/IncreaseReturnValue.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/LazyTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/MultiplyReturnValue.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/PerThisAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/ResourceArrayFactoryBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/RetryAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/RetryableException.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/TestAnnotation.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/TestBeanAdvisor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/UnreliableBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/afterThrowingAdviceTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/annotationPointcut.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/around-advice-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspects.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsPlusAdvisor.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsWithAbstractBean.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsWithCGLIB.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsWithOrdering.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/ataspectj-around-advice-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/BenchmarkTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/MultiplyReturnValueInterceptor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/TraceAfterReturningAdvice.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/TraceAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/TraceBeforeAdvice.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/aspectj.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/springAop.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/lazy.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/pertarget.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/perthis.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/retryAspect.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/SPR3064Tests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/Service.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/ServiceImpl.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/Transaction.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/TransactionInterceptor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/annotationbinding-spr3064.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/twoAdviceAspect.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/twoAdviceAspectPrototype.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/usesInclude.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/usesJoinPointAspect.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/bean-name-pointcut-atAspect-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/AfterReturningGenericTypeMatchingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/GenericBridgeMethodMatchingClassProxyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/GenericBridgeMethodMatchingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/GenericParameterMatchingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/afterReturningGenericTypeMatchingTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/genericBridgeMethodMatchingTests-classProxy-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/genericBridgeMethodMatchingTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/genericParameterMatchingTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/implicit-jp-argument-matching-atAspectJ-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-aspect-property-after-aspect-test.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-aspect-property-before-aspect-test.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-atAspectJ-aspect-property-after-aspect-test.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-atAspectJ-aspect-property-before-aspect-test.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/this-and-target-selectionOnly-pointcuts-atAspectJ-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/CustomEnum.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/GenericBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/GenericIntegerBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/GenericSetOfIntegerBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/AnnotationBeanWiringInfoResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/CustomAutowireConfigurerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/MyRequired.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/RequiredTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/customAutowireConfigurer.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithAllRequiredPropertiesProvided.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithCustomAnnotation.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithOneRequiredPropertyOmitted.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithThreeRequiredPropertiesOmitted.xml delete mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/MethodInvokingFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/GenericBeanFactoryAccessorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/MyAnnotation.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/SomeAnnotatedBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/genericBeanFactoryAccessorTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/serviceloader/ServiceLoaderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireBeanFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/genericBeanTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/QualifierAnnotationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/qualifierAnnotationTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AnnotationBeanNameGeneratorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AnnotationProcessorPerformanceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AnnotationScopeMetadataResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AutowiredQualifierFooService.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerScopeTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserBeanDefinitionDefaultsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserScopedProxyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserWithUserDefinedStrategiesTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/CustomComponent.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/CustomStereotype.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/DefaultNamedComponent.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/DoubleScanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/FooDao.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/FooService.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/FooServiceImpl.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/InvalidConstructorTestBeanNameGenerator.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/MessageBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/NamedComponent.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/NamedStubDao.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ScopedProxyTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ServiceInvocationCounter.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/SimpleConfigTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/SimpleScanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/Spr3775InitDestroyLifecycleTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/StubFooDao.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/TestBeanNameGenerator.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/TestScopeMetadataResolver.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/aspectjTypeFilterTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/componentScanWithAutowiredQualifierTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customAnnotationUsedForBothComponentScanAndQualifierTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customNameGeneratorTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customScopeResolverTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customTypeFilterTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireByNameTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireByTypeTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireConstructorTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireNoTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultDependencyCheckAllTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultDependencyCheckObjectsWithAutowireByNameTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultInitAndDestroyMethodsTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultLazyInitFalseTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultLazyInitTrueTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultNonExistingInitAndDestroyMethodsTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultWithNoOverridesTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/doubleScanTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/invalidClassNameScopeResolverTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/invalidConstructorNameGeneratorTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ltw/ComponentScanningWithLTWTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ltw/ComponentScanningWithLTWTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/matchingResourcePatternTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/nonMatchingResourcePatternTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyDefaultTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyInterfacesTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyInvalidConfigTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyNoTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyTargetClassTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/simpleConfigTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation/simpleScanTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation2/NamedStubDao2.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/annotation3/StubFooDao.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/AbstractGenericsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/BridgeMethodResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/GenericCollectionTypeResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/type/AnnotationTypeFilterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/type/AspectJTypeFilterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/type/AssignableTypeFilterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/type/ClassloadingAssertions.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ejb/access/LocalSlsbInvokerInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ejb/access/LocalStatelessSessionProxyFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ejb/access/SimpleRemoteSlsbInvokerInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ejb/access/SimpleRemoteStatelessSessionProxyFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ejb/config/JeeNamespaceHandlerEventTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ejb/config/JeeNamespaceHandlerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ejb/config/jeeNamespaceHandlerTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ejb/support/EjbSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/InstrumentableClassLoaderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/ReflectiveLoadTimeWeaverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/ResourceOverridingShadowingClassLoaderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/glassfish/GlassFishLoadTimeWeaverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/oc4j/OC4JClassPreprocessorAdapterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/oc4j/OC4JLoadTimeWeaverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/testResource.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/CallMetaDataContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/ParameterizedBeanPropertyRowMapperTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/SimpleJdbcCallTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/SimpleJdbcInsertTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/SimpleJdbcTemplateTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/TableMetaDataContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/AnnotationLazyInitMBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/AnnotationMetadataAssemblerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/JmxUtilsAnnotationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/annotations.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/componentScan.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/lazyAssembling.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/lazyNaming.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/ibatis/SqlMapClientTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/ibatis/support/LobTypeHandlerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/AbstractContainerEntityManagerFactoryIntegrationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryIntegrationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/ApplicationManagedEntityManagerIntegrationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/ContainerManagedEntityManagerIntegrationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/DefaultJpaDialectTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/EntityManagerFactoryBeanSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/EntityManagerFactoryUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/JpaInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/JpaTemplateTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/JpaTransactionManagerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/META-INF/persistence.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/ContextualPerson.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/DriversLicense.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/Person.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/persistence-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/persistence-multi.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/persistence.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/eclipselink/EclipseLinkEntityManagerFactoryIntegrationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/eclipselink/eclipselink-manager.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/HibernateMultiEntityManagerFactoryIntegrationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/hibernate-manager-multi.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/hibernate-manager.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/inject.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/jpa-archive.jar create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/memdb.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/multi-jpa-emf.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/OpenJpaEntityManagerFactoryIntegrationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/OpenJpaEntityManagerFactoryWithAspectJWeavingIntegrationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/openjpa-manager-aspectj-weaving.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/openjpa-manager.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-complex.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example1.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example2.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example3.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example4.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example5.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example6.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-invalid.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-no-schema.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceXmlParsingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/JpaDaoSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/PersistenceInjectionIntegrationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/PersistenceInjectionTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/SharedEntityManagerFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/TopLinkEntityManagerFactoryIntegrationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/TopLinkMultiEntityManagerFactoryIntegrationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/toplink-manager-multi.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/toplink-manager.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/remoting/caucho/CauchoRemotingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/JaxWsSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/OrderNotFoundException.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/OrderService.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/OrderServiceImpl.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scheduling/concurrent/ScheduledExecutorFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/annotation/ProfileValueAnnotationAwareTransactionalTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/annotation/ProfileValueAnnotationAwareTransactionalTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/SpringRunnerContextCacheTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/TestContextManagerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/TestExecutionListenersTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/ConcreteTransactionalJUnit38SpringContextTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/ConcreteTransactionalJUnit38SpringContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/FailingBeforeAndAfterMethodsTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/FailingBeforeAndAfterMethodsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/ProfileValueJUnit38SpringContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/RepeatedJUnit38SpringContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/AbsolutePathSpringJUnit4ClassRunnerAppCtxTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/AbstractTransactionalSpringRunnerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/BeforeAndAfterTransactionAnnotationTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/BeforeAndAfterTransactionAnnotationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassLevelDisabledSpringRunnerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassLevelTransactionalSpringRunnerTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassLevelTransactionalSpringRunnerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ConcreteTransactionalJUnit4SpringContextTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ConcreteTransactionalJUnit4SpringContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackFalseTransactionalSpringRunnerTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackFalseTransactionalSpringRunnerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackTrueTransactionalSpringRunnerTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackTrueTransactionalSpringRunnerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/EnabledAndIgnoredSpringRunnerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/FailingBeforeAndAfterMethodsTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/FailingBeforeAndAfterMethodsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/HardCodedProfileValueSourceSpringRunnerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/InheritedConfigSpringJUnit4ClassRunnerAppCtxTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MethodLevelTransactionalSpringRunnerTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MethodLevelTransactionalSpringRunnerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context1.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context2.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context3.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ParameterizedDependencyInjectionTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ParameterizedDependencyInjectionTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests-context.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RelativePathSpringJUnit4ClassRunnerAppCtxTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RepeatedSpringMethodRoadieTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/StandardJUnit4FeaturesSpringRunnerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/StandardJUnit4FeaturesTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/TimedTransactionalSpringRunnerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/BeanOverridingDefaultLocationsInheritedTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/BeanOverridingDefaultLocationsInheritedTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/BeanOverridingExplicitLocationsInheritedTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsBaseTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsBaseTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsInheritedTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsInheritedTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/ExplicitLocationsBaseTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/ExplicitLocationsInheritedTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/Spr3896SuiteTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/transactionalTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/support/CustomizedGenericXmlContextLoaderTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/support/CustomizedGenericXmlContextLoaderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/support/GenericXmlContextLoaderResourceLocationsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/ConcreteTransactionalTestNGSpringContextTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/ConcreteTransactionalTestNGSpringContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/DirtiesContextTransactionalTestNGSpringContextTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/DirtiesContextTransactionalTestNGSpringContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/FailingBeforeAndAfterMethodsTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/FailingBeforeAndAfterMethodsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionNamespaceHandlerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/annotationTransactionNamespaceHandlerTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/config/AnnotationDrivenTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/config/TransactionalService.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/config/annotationDrivenProxyTargetClassTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/TypeUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/annotation/PortletAnnotationControllerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/AdminController.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/BuyForm.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/ControllerClassNameHandlerMappingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/IndexController.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/MethodNameDispatchingController.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/WelcomeController.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/class-mapping.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/OptionTagEnumTests.java diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutAtAspectTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutAtAspectTests.java new file mode 100644 index 00000000000..be9b3057597 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutAtAspectTests.java @@ -0,0 +1,117 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; + +import org.springframework.aop.aspectj.annotation.AspectJProxyFactory; +import org.springframework.aop.framework.Advised; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * Test for correct application of the bean() PCD for @AspectJ-based aspects. + * + * @author Ramnivas Laddad + * @author Juergen Hoeller + */ +public class BeanNamePointcutAtAspectTests extends AbstractDependencyInjectionSpringContextTests { + + protected ITestBean testBean1; + + protected ITestBean testBean2; + + protected ITestBean testBean3; + + protected CounterAspect counterAspect; + + + public BeanNamePointcutAtAspectTests() { + setPopulateProtectedVariables(true); + } + + protected String getConfigPath() { + return "bean-name-pointcut-atAspect-tests.xml"; + } + + protected void onSetUp() throws Exception { + counterAspect.count = 0; + super.onSetUp(); + } + + + public void testMatchingBeanName() { + assertTrue("Expected a proxy", testBean1 instanceof Advised); + // Call two methods to test for SPR-3953-like condition + testBean1.setAge(20); + testBean1.setName(""); + assertEquals(2 /*TODO: make this 3 when upgrading to AspectJ 1.6.0 and advice in CounterAspect are uncommented*/, counterAspect.count); + } + + public void testNonMatchingBeanName() { + assertFalse("Didn't expect a proxy", testBean3 instanceof Advised); + testBean3.setAge(20); + assertEquals(0, counterAspect.count); + } + + public void testProgrammaticProxyCreation() { + ITestBean testBean = new TestBean(); + + AspectJProxyFactory factory = new AspectJProxyFactory(); + factory.setTarget(testBean); + + CounterAspect myCounterAspect = new CounterAspect(); + factory.addAspect(myCounterAspect); + + ITestBean proxyTestBean = factory.getProxy(); + + assertTrue("Expected a proxy", proxyTestBean instanceof Advised); + proxyTestBean.setAge(20); + assertEquals("Programmatically created proxy shouldn't match bean()", 0, myCounterAspect.count); + } + + + @Aspect + public static class CounterAspect { + + int count; + + @Before("execution(* set*(..)) && bean(testBean1)") + public void increment1ForAnonymousPointcut() { + count++; + } + +// @Pointcut("execution(* setAge(..)) && bean(testBean1)") +// public void testBean1SetAge() {} +// +// @Pointcut("execution(* setAge(..)) && bean(testBean2)") +// public void testBean2SetAge() {} +// +// @Before("testBean1SetAge()") +// public void increment1() { +// count++; +// } +// +// @Before("testBean2SetAge()") +// public void increment2() { +// count++; +// } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ImplicitJPArgumentMatchingAtAspectJTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ImplicitJPArgumentMatchingAtAspectJTests.java new file mode 100644 index 00000000000..d030b294a55 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ImplicitJPArgumentMatchingAtAspectJTests.java @@ -0,0 +1,55 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.aop.aspectj; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.beans.TestBean; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * Tests to check if the first implicit join point argument is correctly processed. + * See SPR-3723 for more details. + * + * @author Ramnivas Laddad + */ +public class ImplicitJPArgumentMatchingAtAspectJTests extends AbstractDependencyInjectionSpringContextTests { + protected TestBean testBean; + + public ImplicitJPArgumentMatchingAtAspectJTests() { + setPopulateProtectedVariables(true); + } + + protected String getConfigPath() { + return "implicit-jp-argument-matching-atAspectJ-tests.xml"; + } + + public void testAspect() { + // nothing to really test; it is enough if we don't get error while creating app context + testBean.setCountry("US"); + } + + @Aspect + public static class CounterAtAspectJAspect { + @Around(value="execution(* org.springframework.beans.TestBean.*(..)) and this(bean) and args(argument)", + argNames="bean,argument") + public void increment(ProceedingJoinPoint pjp, TestBean bean, Object argument) throws Throwable { + pjp.proceed(); + } + } +} + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/JoinPointMonitorAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/JoinPointMonitorAspect.java new file mode 100644 index 00000000000..0b23dbd0748 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/JoinPointMonitorAspect.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj; + +import org.aspectj.lang.ProceedingJoinPoint; + +/** + * @author Ramnivas Laddad + */ +public class JoinPointMonitorAspect { + + /** + * The counter property is purposefully not used in the aspect to avoid distraction + * from the main bug -- merely needing a dependency on an advised bean + * is sufficient to reproduce the bug. + */ + private ICounter counter; + + int beforeExecutions; + int aroundExecutions; + + public void before() { + beforeExecutions++; + } + + public Object around(ProceedingJoinPoint pjp) throws Throwable { + aroundExecutions++; + return pjp.proceed(); + } + + public ICounter getCounter() { + return counter; + } + + public void setCounter(ICounter counter) { + this.counter = counter; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/JoinPointMonitorAtAspectJAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/JoinPointMonitorAtAspectJAspect.java new file mode 100644 index 00000000000..bbb6b3338d5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/JoinPointMonitorAtAspectJAspect.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; + +/** + * @author Ramnivas Laddad + * @since 2.0 + */ +@Aspect +public class JoinPointMonitorAtAspectJAspect { + /* The counter property is purposefully not used in the aspect to avoid distraction + * from the main bug -- merely needing a dependency on an advised bean + * is sufficient to reproduce the bug. + */ + private ICounter counter; + + int beforeExecutions; + int aroundExecutions; + + @Before("execution(* increment*())") + public void before() { + beforeExecutions++; + } + + @Around("execution(* increment*())") + public Object around(ProceedingJoinPoint pjp) throws Throwable { + aroundExecutions++; + return pjp.proceed(); + } + + public ICounter getCounter() { + return counter; + } + + public void setCounter(ICounter counter) { + this.counter = counter; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/PropertyDependentAspectTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/PropertyDependentAspectTests.java new file mode 100644 index 00000000000..3fc5c6fa861 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/PropertyDependentAspectTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.Advised; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Check that an aspect that depends on another bean, where the referenced bean + * itself is advised by the same aspect, works correctly. + * + * @author Ramnivas Laddad + * @author Juergen Hoeller + */ +public class PropertyDependentAspectTests extends TestCase { + + public void testPropertyDependentAspectWithPropertyDeclaredBeforeAdvice() throws Exception { + checkXmlAspect("org/springframework/aop/aspectj/property-dependent-aspect-property-before-aspect-test.xml"); + } + + public void testPropertyDependentAspectWithPropertyDeclaredAfterAdvice() throws Exception { + checkXmlAspect("org/springframework/aop/aspectj/property-dependent-aspect-property-after-aspect-test.xml"); + } + + public void testPropertyDependentAtAspectJAspectWithPropertyDeclaredBeforeAdvice() throws Exception { + checkAtAspectJAspect("org/springframework/aop/aspectj/property-dependent-atAspectJ-aspect-property-before-aspect-test.xml"); + } + + public void testPropertyDependentAtAspectJAspectWithPropertyDeclaredAfterAdvice() throws Exception { + checkAtAspectJAspect("org/springframework/aop/aspectj/property-dependent-atAspectJ-aspect-property-after-aspect-test.xml"); + } + + private void checkXmlAspect(String appContextFile) { + ApplicationContext context = new ClassPathXmlApplicationContext(appContextFile); + ICounter counter = (ICounter) context.getBean("counter"); + assertTrue("Proxy didn't get created", counter instanceof Advised); + + counter.increment(); + JoinPointMonitorAspect callCountingAspect = (JoinPointMonitorAspect)context.getBean("monitoringAspect"); + assertEquals("Advise didn't get executed", 1, callCountingAspect.beforeExecutions); + assertEquals("Advise didn't get executed", 1, callCountingAspect.aroundExecutions); + } + + private void checkAtAspectJAspect(String appContextFile) { + ApplicationContext context = new ClassPathXmlApplicationContext(appContextFile); + ICounter counter = (ICounter) context.getBean("counter"); + assertTrue("Proxy didn't get created", counter instanceof Advised); + + counter.increment(); + JoinPointMonitorAtAspectJAspect callCountingAspect = (JoinPointMonitorAtAspectJAspect)context.getBean("monitoringAspect"); + assertEquals("Advise didn't get executed", 1, callCountingAspect.beforeExecutions); + assertEquals("Advise didn't get executed", 1, callCountingAspect.aroundExecutions); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.java new file mode 100644 index 00000000000..ad19554bac0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.java @@ -0,0 +1,195 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Ramnivas Laddad + */ +public class ThisAndTargetSelectionOnlyPointcutsAtAspectJTests extends AbstractDependencyInjectionSpringContextTests { + protected TestInterface testBean; + protected TestInterface testAnnotatedClassBean; + protected TestInterface testAnnotatedMethodBean; + + protected Counter counter; + + public ThisAndTargetSelectionOnlyPointcutsAtAspectJTests() { + setPopulateProtectedVariables(true); + } + + @Override + protected void onSetUp() throws Exception { + super.onSetUp(); + counter.reset(); + } + + protected String getConfigPath() { + return "this-and-target-selectionOnly-pointcuts-atAspectJ-tests.xml"; + } + + public void testThisAsClassDoesNotMatch() { + testBean.doIt(); + assertEquals(0, counter.thisAsClassCounter); + } + + public void testThisAsInterfaceMatch() { + testBean.doIt(); + assertEquals(1, counter.thisAsInterfaceCounter); + } + + public void testTargetAsClassDoesMatch() { + testBean.doIt(); + assertEquals(1, counter.targetAsClassCounter); + } + + public void testTargetAsInterfaceMatch() { + testBean.doIt(); + assertEquals(1, counter.targetAsInterfaceCounter); + } + + public void testThisAsClassAndTargetAsClassCounterNotMatch() { + testBean.doIt(); + assertEquals(0, counter.thisAsClassAndTargetAsClassCounter); + } + + public void testThisAsInterfaceAndTargetAsInterfaceCounterMatch() { + testBean.doIt(); + assertEquals(1, counter.thisAsInterfaceAndTargetAsInterfaceCounter); + } + + public void testThisAsInterfaceAndTargetAsClassCounterMatch() { + testBean.doIt(); + assertEquals(1, counter.thisAsInterfaceAndTargetAsInterfaceCounter); + } + + + public void testAtTargetClassAnnotationMatch() { + testAnnotatedClassBean.doIt(); + assertEquals(1, counter.atTargetClassAnnotationCounter); + } + + public void testAtAnnotationMethodAnnotationMatch() { + testAnnotatedMethodBean.doIt(); + assertEquals(1, counter.atAnnotationMethodAnnotationCounter); + } + + public static interface TestInterface { + public void doIt(); + } + + public static class TestImpl implements TestInterface { + public void doIt() { + } + } + + @Retention(RetentionPolicy.RUNTIME) + public static @interface TestAnnotation { + + } + + @TestAnnotation + public static class AnnotatedClassTestImpl implements TestInterface { + public void doIt() { + } + } + + public static class AnnotatedMethodTestImpl implements TestInterface { + @TestAnnotation + public void doIt() { + } + } + + @Aspect + public static class Counter { + int thisAsClassCounter; + int thisAsInterfaceCounter; + int targetAsClassCounter; + int targetAsInterfaceCounter; + int thisAsClassAndTargetAsClassCounter; + int thisAsInterfaceAndTargetAsInterfaceCounter; + int thisAsInterfaceAndTargetAsClassCounter; + int atTargetClassAnnotationCounter; + int atAnnotationMethodAnnotationCounter; + + public void reset() { + thisAsClassCounter = 0; + thisAsInterfaceCounter = 0; + targetAsClassCounter = 0; + targetAsInterfaceCounter = 0; + thisAsClassAndTargetAsClassCounter = 0; + thisAsInterfaceAndTargetAsInterfaceCounter = 0; + thisAsInterfaceAndTargetAsClassCounter = 0; + atTargetClassAnnotationCounter = 0; + atAnnotationMethodAnnotationCounter = 0; + } + + @Before("this(org.springframework.aop.aspectj.ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.TestImpl)") + public void incrementThisAsClassCounter() { + thisAsClassCounter++; + } + + @Before("this(org.springframework.aop.aspectj.ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.TestInterface)") + public void incrementThisAsInterfaceCounter() { + thisAsInterfaceCounter++; + } + + @Before("target(org.springframework.aop.aspectj.ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.TestImpl)") + public void incrementTargetAsClassCounter() { + targetAsClassCounter++; + } + + @Before("target(org.springframework.aop.aspectj.ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.TestInterface)") + public void incrementTargetAsInterfaceCounter() { + targetAsInterfaceCounter++; + } + + @Before("this(org.springframework.aop.aspectj.ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.TestImpl) " + + "&& target(org.springframework.aop.aspectj.ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.TestImpl)") + public void incrementThisAsClassAndTargetAsClassCounter() { + thisAsClassAndTargetAsClassCounter++; + } + + @Before("this(org.springframework.aop.aspectj.ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.TestInterface) " + + "&& target(org.springframework.aop.aspectj.ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.TestInterface)") + public void incrementThisAsInterfaceAndTargetAsInterfaceCounter() { + thisAsInterfaceAndTargetAsInterfaceCounter++; + } + + @Before("this(org.springframework.aop.aspectj.ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.TestInterface) " + + "&& target(org.springframework.aop.aspectj.ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.TestImpl)") + public void incrementThisAsInterfaceAndTargetAsClassCounter() { + thisAsInterfaceAndTargetAsClassCounter++; + } + + @Before("@target(org.springframework.aop.aspectj.ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.TestAnnotation)") + public void incrementAtTargetClassAnnotationCounter() { + atTargetClassAnnotationCounter++; + } + + @Before("@annotation(org.springframework.aop.aspectj.ThisAndTargetSelectionOnlyPointcutsAtAspectJTests.TestAnnotation)") + public void incrementAtAnnotationMethodAnnotationCounter() { + atAnnotationMethodAnnotationCounter++; + } + + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TigerAspectJAdviceParameterNameDiscovererTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TigerAspectJAdviceParameterNameDiscovererTests.java new file mode 100644 index 00000000000..26268b115c5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TigerAspectJAdviceParameterNameDiscovererTests.java @@ -0,0 +1,78 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj; + +import org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException; + +/** + * Tests just the annotation binding part of AspectJAdviceParameterNameDiscoverer; + * see supertype for remaining tests. + * + * @author Adrian Colyer + */ +public class TigerAspectJAdviceParameterNameDiscovererTests extends AspectJAdviceParameterNameDiscovererTests { + + public void testAtThis() { + assertParameterNames(getMethod("oneAnnotation"),"@this(a)",new String[]{"a"}); + } + + public void testAtTarget() { + assertParameterNames(getMethod("oneAnnotation"),"@target(a)",new String[]{"a"}); + } + + public void testAtArgs() { + assertParameterNames(getMethod("oneAnnotation"),"@args(a)",new String[]{"a"}); + } + + public void testAtWithin() { + assertParameterNames(getMethod("oneAnnotation"),"@within(a)",new String[]{"a"}); + } + + public void testAtWithincode() { + assertParameterNames(getMethod("oneAnnotation"),"@withincode(a)",new String[]{"a"}); + } + + public void testAtAnnotation() { + assertParameterNames(getMethod("oneAnnotation"),"@annotation(a)",new String[]{"a"}); + } + + public void testAmbiguousAnnotationTwoVars() { + assertException(getMethod("twoAnnotations"),"@annotation(a) && @this(x)",AmbiguousBindingException.class, + "Found 2 potential annotation variable(s), and 2 potential argument slots"); + } + + public void testAmbiguousAnnotationOneVar() { + assertException(getMethod("oneAnnotation"),"@annotation(a) && @this(x)",IllegalArgumentException.class, + "Found 2 candidate annotation binding variables but only one potential argument binding slot"); + } + + public void testAnnotationMedley() { + assertParameterNames(getMethod("annotationMedley"),"@annotation(a) && args(count) && this(foo)",null,"ex", + new String[] {"ex","foo","count","a"}); + } + + + public void oneAnnotation(MyAnnotation ann) {} + + public void twoAnnotations(MyAnnotation ann, MyAnnotation anotherAnn) {} + + public void annotationMedley(Throwable t, Object foo, int x, MyAnnotation ma) {} + + + @interface MyAnnotation {} + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TigerAspectJExpressionPointcutTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TigerAspectJExpressionPointcutTests.java new file mode 100644 index 00000000000..de49610926f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TigerAspectJExpressionPointcutTests.java @@ -0,0 +1,261 @@ +/* + * Copyright 2002-2005 the original author 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.aop.aspectj; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.transaction.annotation.AnnotationTransactionAttributeSourceTests; +import org.springframework.transaction.annotation.AnnotationTransactionAttributeSourceTests.TestBean3; +import org.springframework.transaction.annotation.AnnotationTransactionAttributeSourceTests.TestBean4; +import org.springframework.transaction.annotation.Transactional; + +/** + * Java5-specific AspectJExpressionPointcutTests. + * + * @author Rod Johnson + */ +public class TigerAspectJExpressionPointcutTests extends TestCase { + + // TODO factor into static in AspectJExpressionPointcut + private Method getAge; + + private Map methodsOnHasGeneric = new HashMap(); + + + public void setUp() throws NoSuchMethodException { + getAge = TestBean.class.getMethod("getAge", (Class[]) null); + // Assumes no overloading + for (Method m : HasGeneric.class.getMethods()) { + methodsOnHasGeneric.put(m.getName(), m); + } + } + + + public static class HasGeneric { + + public void setFriends(List friends) { + } + public void setEnemies(List enemies) { + } + public void setPartners(List partners) { + } + public void setPhoneNumbers(List numbers) { + } + } + + public void testMatchGenericArgument() { + String expression = "execution(* set*(java.util.List) )"; + AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(); + ajexp.setExpression(expression); + + // TODO this will currently map, would be nice for optimization + //assertTrue(ajexp.matches(HasGeneric.class)); + //assertFalse(ajexp.matches(TestBean.class)); + + Method takesGenericList = methodsOnHasGeneric.get("setFriends"); + assertTrue(ajexp.matches(takesGenericList, HasGeneric.class)); + assertTrue(ajexp.matches(methodsOnHasGeneric.get("setEnemies"), HasGeneric.class)); + assertFalse(ajexp.matches(methodsOnHasGeneric.get("setPartners"), HasGeneric.class)); + assertFalse(ajexp.matches(methodsOnHasGeneric.get("setPhoneNumbers"), HasGeneric.class)); + + assertFalse(ajexp.matches(getAge, TestBean.class)); + } + + public void testMatchVarargs() throws SecurityException, NoSuchMethodException { + String expression = "execution(int *.*(String, Object...) )"; + AspectJExpressionPointcut jdbcVarArgs = new AspectJExpressionPointcut(); + jdbcVarArgs.setExpression(expression); + + assertFalse(jdbcVarArgs.matches( + JdbcTemplate.class.getMethod("queryForInt", String.class, Object[].class), + JdbcTemplate.class)); + + assertTrue(jdbcVarArgs.matches( + SimpleJdbcTemplate.class.getMethod("queryForInt", String.class, Object[].class), + SimpleJdbcTemplate.class)); + + Method takesGenericList = methodsOnHasGeneric.get("setFriends"); + assertFalse(jdbcVarArgs.matches(takesGenericList, HasGeneric.class)); + assertFalse(jdbcVarArgs.matches(methodsOnHasGeneric.get("setEnemies"), HasGeneric.class)); + assertFalse(jdbcVarArgs.matches(methodsOnHasGeneric.get("setPartners"), HasGeneric.class)); + assertFalse(jdbcVarArgs.matches(methodsOnHasGeneric.get("setPhoneNumbers"), HasGeneric.class)); + assertFalse(jdbcVarArgs.matches(getAge, TestBean.class)); + } + + public void testMatchAnnotationOnClassWithAtWithin() throws SecurityException, NoSuchMethodException { + String expression = "@within(org.springframework.transaction.annotation.Transactional)"; + testMatchAnnotationOnClass(expression); + } + + public void testMatchAnnotationOnClassWithoutBinding() throws SecurityException, NoSuchMethodException { + String expression = "within(@org.springframework.transaction.annotation.Transactional *)"; + testMatchAnnotationOnClass(expression); + } + + public void testMatchAnnotationOnClassWithSubpackageWildcard() throws SecurityException, NoSuchMethodException { + String expression = "within(@(org.springframework..*) *)"; + AspectJExpressionPointcut springAnnotatedPc = testMatchAnnotationOnClass(expression); + assertFalse(springAnnotatedPc.matches(TestBean.class.getMethod("setName", String.class), + TestBean.class)); + assertTrue(springAnnotatedPc.matches(SpringAnnotated.class.getMethod("foo", (Class[]) null), + SpringAnnotated.class)); + + expression = "within(@(org.springframework.transaction..*) *)"; + AspectJExpressionPointcut springTxAnnotatedPc = testMatchAnnotationOnClass(expression); + assertFalse(springTxAnnotatedPc.matches(SpringAnnotated.class.getMethod("foo", (Class[]) null), + SpringAnnotated.class)); + } + + public void testMatchAnnotationOnClassWithExactPackageWildcard() throws SecurityException, NoSuchMethodException { + String expression = "within(@(org.springframework.transaction.annotation.*) *)"; + testMatchAnnotationOnClass(expression); + } + + private AspectJExpressionPointcut testMatchAnnotationOnClass(String expression) throws SecurityException, NoSuchMethodException { + AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(); + ajexp.setExpression(expression); + + assertFalse(ajexp.matches(getAge, TestBean.class)); + assertTrue(ajexp.matches(HasTransactionalAnnotation.class.getMethod("foo", (Class[]) null), HasTransactionalAnnotation.class)); + assertTrue(ajexp.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)); + assertTrue(ajexp.matches(AnnotationTransactionAttributeSourceTests.TestBean4.class.getMethod("setName", String.class), TestBean4.class)); + assertFalse(ajexp.matches(AnnotationTransactionAttributeSourceTests.TestBean3.class.getMethod("setName", String.class), TestBean3.class)); + return ajexp; + } + + public void testAnnotationOnMethodWithFQN() throws SecurityException, NoSuchMethodException { + String expression = "@annotation(org.springframework.transaction.annotation.Transactional)"; + AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(); + ajexp.setExpression(expression); + + assertFalse(ajexp.matches(getAge, TestBean.class)); + assertFalse(ajexp.matches(HasTransactionalAnnotation.class.getMethod("foo", (Class[]) null), HasTransactionalAnnotation.class)); + assertFalse(ajexp.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)); + assertFalse(ajexp.matches(AnnotationTransactionAttributeSourceTests.TestBean3.class.getMethod("setName", String.class), TestBean3.class)); + assertTrue(ajexp.matches(AnnotationTransactionAttributeSourceTests.TestBean3.class.getMethod("getAge", (Class[]) null), TestBean3.class)); + assertFalse(ajexp.matches(AnnotationTransactionAttributeSourceTests.TestBean3.class.getMethod("setName", String.class), TestBean3.class)); + } + + public void testAnnotationOnMethodWithWildcard() throws SecurityException, NoSuchMethodException { + String expression = "execution(@(org.springframework..*) * *(..))"; + AspectJExpressionPointcut anySpringMethodAnnotation = new AspectJExpressionPointcut(); + anySpringMethodAnnotation.setExpression(expression); + + assertFalse(anySpringMethodAnnotation.matches(getAge, TestBean.class)); + assertFalse(anySpringMethodAnnotation.matches(HasTransactionalAnnotation.class.getMethod("foo", (Class[]) null), HasTransactionalAnnotation.class)); + assertFalse(anySpringMethodAnnotation.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)); + assertFalse(anySpringMethodAnnotation.matches(AnnotationTransactionAttributeSourceTests.TestBean3.class.getMethod("setName", String.class), TestBean3.class)); + assertTrue(anySpringMethodAnnotation.matches(AnnotationTransactionAttributeSourceTests.TestBean3.class.getMethod("getAge", (Class[]) null), TestBean3.class)); + assertFalse(anySpringMethodAnnotation.matches(AnnotationTransactionAttributeSourceTests.TestBean3.class.getMethod("setName", String.class), TestBean3.class)); + } + + public void testAnnotationOnMethodArgumentsWithFQN() throws SecurityException, NoSuchMethodException { + String expression = "@args(*, org.springframework.aop.aspectj.TigerAspectJExpressionPointcutTests.EmptySpringAnnotation))"; + AspectJExpressionPointcut takesSpringAnnotatedArgument2 = new AspectJExpressionPointcut(); + takesSpringAnnotatedArgument2.setExpression(expression); + + assertFalse(takesSpringAnnotatedArgument2.matches(getAge, TestBean.class)); + assertFalse(takesSpringAnnotatedArgument2.matches(HasTransactionalAnnotation.class.getMethod("foo", (Class[]) null), HasTransactionalAnnotation.class)); + assertFalse(takesSpringAnnotatedArgument2.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)); + assertFalse(takesSpringAnnotatedArgument2.matches(AnnotationTransactionAttributeSourceTests.TestBean3.class.getMethod("setName", String.class), TestBean3.class)); + assertFalse(takesSpringAnnotatedArgument2.matches(AnnotationTransactionAttributeSourceTests.TestBean3.class.getMethod("getAge", (Class[]) null), TestBean3.class)); + assertFalse(takesSpringAnnotatedArgument2.matches(AnnotationTransactionAttributeSourceTests.TestBean3.class.getMethod("setName", String.class), TestBean3.class)); + + assertTrue(takesSpringAnnotatedArgument2.matches( + ProcessesSpringAnnotatedParameters.class.getMethod("takesAnnotatedParameters", TestBean.class, SpringAnnotated.class), + ProcessesSpringAnnotatedParameters.class)); + + // True because it maybeMatches with potential argument subtypes + assertTrue(takesSpringAnnotatedArgument2.matches( + ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, TestBean3.class), + ProcessesSpringAnnotatedParameters.class)); + + assertFalse(takesSpringAnnotatedArgument2.matches( + ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, TestBean3.class), + ProcessesSpringAnnotatedParameters.class, + new Object[] { new TestBean(), new TestBean3()}) + ); + } + + public void testAnnotationOnMethodArgumentsWithWildcards() throws SecurityException, NoSuchMethodException { + String expression = "execution(* *(*, @(org.springframework..*) *))"; + AspectJExpressionPointcut takesSpringAnnotatedArgument2 = new AspectJExpressionPointcut(); + takesSpringAnnotatedArgument2.setExpression(expression); + + assertFalse(takesSpringAnnotatedArgument2.matches(getAge, TestBean.class)); + assertFalse(takesSpringAnnotatedArgument2.matches(HasTransactionalAnnotation.class.getMethod("foo", (Class[]) null), HasTransactionalAnnotation.class)); + assertFalse(takesSpringAnnotatedArgument2.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)); + assertFalse(takesSpringAnnotatedArgument2.matches(AnnotationTransactionAttributeSourceTests.TestBean3.class.getMethod("setName", String.class), TestBean3.class)); + assertFalse(takesSpringAnnotatedArgument2.matches(AnnotationTransactionAttributeSourceTests.TestBean3.class.getMethod("getAge", (Class[]) null), TestBean3.class)); + assertFalse(takesSpringAnnotatedArgument2.matches(AnnotationTransactionAttributeSourceTests.TestBean3.class.getMethod("setName", String.class), TestBean3.class)); + + assertTrue(takesSpringAnnotatedArgument2.matches( + ProcessesSpringAnnotatedParameters.class.getMethod("takesAnnotatedParameters", TestBean.class, SpringAnnotated.class), + ProcessesSpringAnnotatedParameters.class)); + assertFalse(takesSpringAnnotatedArgument2.matches( + ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, TestBean3.class), + ProcessesSpringAnnotatedParameters.class)); + } + + + public static class ProcessesSpringAnnotatedParameters { + + public void takesAnnotatedParameters(TestBean tb, SpringAnnotated sa) { + } + + public void takesNoAnnotatedParameters(TestBean tb, TestBean3 tb3) { + } + } + + + @Transactional + public static class HasTransactionalAnnotation { + + public void foo() { + } + public Object bar(String foo) { + throw new UnsupportedOperationException(); + } + } + + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + public @interface EmptySpringAnnotation { + + } + + + @EmptySpringAnnotation + public static class SpringAnnotated { + public void foo() { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactoryTests.java new file mode 100644 index 00000000000..44c3f73a482 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactoryTests.java @@ -0,0 +1,903 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.annotation; + +import java.lang.reflect.UndeclaredThrowableException; +import java.rmi.RemoteException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import javax.servlet.ServletException; + +import junit.framework.TestCase; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.After; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.DeclarePrecedence; +import org.aspectj.lang.annotation.Pointcut; + +import org.springframework.aop.Advisor; +import org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor; +import org.springframework.aop.framework.Advised; +import org.springframework.aop.framework.AopConfigException; +import org.springframework.aop.framework.Lockable; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.interceptor.ExposeInvocationInterceptor; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.core.OrderComparator; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; + +/** + * Abstract tests for AspectJAdvisorFactory. + * See subclasses for tests of concrete factories. + * + * @author Rod Johnson + */ +public abstract class AbstractAspectJAdvisorFactoryTests extends TestCase { + + /** + * To be overridden by concrete test subclasses. + * @return the fixture + */ + protected abstract AspectJAdvisorFactory getFixture(); + + + public void testRejectsPerCflowAspect() { + try { + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerCflowAspect(),"someBean")); + fail("Cannot accept cflow"); + } + catch (AopConfigException ex) { + assertTrue(ex.getMessage().indexOf("PERCFLOW") != -1); + } + } + + public void testRejectsPerCflowBelowAspect() { + try { + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerCflowBelowAspect(),"someBean")); + fail("Cannot accept cflowbelow"); + } + catch (AopConfigException ex) { + assertTrue(ex.getMessage().indexOf("PERCFLOWBELOW") != -1); + } + } + + public void testPerTargetAspect() throws SecurityException, NoSuchMethodException { + TestBean target = new TestBean(); + int realAge = 65; + target.setAge(realAge); + TestBean itb = (TestBean) createProxy(target, + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerTargetAspect(), "someBean")), + TestBean.class); + assertEquals("Around advice must NOT apply", realAge, itb.getAge()); + + Advised advised = (Advised) itb; + SyntheticInstantiationAdvisor sia = (SyntheticInstantiationAdvisor) advised.getAdvisors()[1]; + assertTrue(sia.getPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null)); + InstantiationModelAwarePointcutAdvisorImpl imapa = (InstantiationModelAwarePointcutAdvisorImpl) advised.getAdvisors()[3]; + LazySingletonAspectInstanceFactoryDecorator maaif = + (LazySingletonAspectInstanceFactoryDecorator) imapa.getAspectInstanceFactory(); + assertFalse(maaif.isMaterialized()); + + // Check that the perclause pointcut is valid + assertTrue(maaif.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null)); + assertNotSame(imapa.getDeclaredPointcut(), imapa.getPointcut()); + + // Hit the method in the per clause to instantiate the aspect + itb.getSpouse(); + + assertTrue(maaif.isMaterialized()); + + assertEquals("Around advice must apply", 0, itb.getAge()); + assertEquals("Around advice must apply", 1, itb.getAge()); + } + + public void testMultiplePerTargetAspects() throws SecurityException, NoSuchMethodException { + TestBean target = new TestBean(); + int realAge = 65; + target.setAge(realAge); + + List advisors = new LinkedList(); + PerTargetAspect aspect1 = new PerTargetAspect(); + aspect1.count = 100; + aspect1.setOrder(10); + advisors.addAll( + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspect1, "someBean1"))); + PerTargetAspect aspect2 = new PerTargetAspect(); + aspect2.setOrder(5); + advisors.addAll( + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspect2, "someBean2"))); + Collections.sort(advisors, new OrderComparator()); + + TestBean itb = (TestBean) createProxy(target, advisors, TestBean.class); + assertEquals("Around advice must NOT apply", realAge, itb.getAge()); + + // Hit the method in the per clause to instantiate the aspect + itb.getSpouse(); + + assertEquals("Around advice must apply", 0, itb.getAge()); + assertEquals("Around advice must apply", 1, itb.getAge()); + } + + public void testMultiplePerTargetAspectsWithOrderAnnotation() throws SecurityException, NoSuchMethodException { + TestBean target = new TestBean(); + int realAge = 65; + target.setAge(realAge); + + List advisors = new LinkedList(); + PerTargetAspectWithOrderAnnotation10 aspect1 = new PerTargetAspectWithOrderAnnotation10(); + aspect1.count = 100; + advisors.addAll( + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspect1, "someBean1"))); + PerTargetAspectWithOrderAnnotation5 aspect2 = new PerTargetAspectWithOrderAnnotation5(); + advisors.addAll( + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspect2, "someBean2"))); + Collections.sort(advisors, new OrderComparator()); + + TestBean itb = (TestBean) createProxy(target, advisors, TestBean.class); + assertEquals("Around advice must NOT apply", realAge, itb.getAge()); + + // Hit the method in the per clause to instantiate the aspect + itb.getSpouse(); + + assertEquals("Around advice must apply", 0, itb.getAge()); + assertEquals("Around advice must apply", 1, itb.getAge()); + } + + public void testPerThisAspect() throws SecurityException, NoSuchMethodException { + TestBean target = new TestBean(); + int realAge = 65; + target.setAge(realAge); + TestBean itb = (TestBean) createProxy(target, + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerThisAspect(), "someBean")), + TestBean.class); + assertEquals("Around advice must NOT apply", realAge, itb.getAge()); + + Advised advised = (Advised) itb; + // Will be ExposeInvocationInterceptor, synthetic instantiation advisor, 2 method advisors + assertEquals(4, advised.getAdvisors().length); + SyntheticInstantiationAdvisor sia = (SyntheticInstantiationAdvisor) advised.getAdvisors()[1]; + assertTrue(sia.getPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null)); + InstantiationModelAwarePointcutAdvisorImpl imapa = (InstantiationModelAwarePointcutAdvisorImpl) advised.getAdvisors()[2]; + LazySingletonAspectInstanceFactoryDecorator maaif = + (LazySingletonAspectInstanceFactoryDecorator) imapa.getAspectInstanceFactory(); + assertFalse(maaif.isMaterialized()); + + // Check that the perclause pointcut is valid + assertTrue(maaif.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null)); + assertNotSame(imapa.getDeclaredPointcut(), imapa.getPointcut()); + + // Hit the method in the per clause to instantiate the aspect + itb.getSpouse(); + + assertTrue(maaif.isMaterialized()); + + assertTrue(imapa.getDeclaredPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getAge"), null)); + + assertEquals("Around advice must apply", 0, itb.getAge()); + assertEquals("Around advice must apply", 1, itb.getAge()); + } + + public void testPerTypeWithinAspect() throws SecurityException, NoSuchMethodException { + TestBean target = new TestBean(); + int realAge = 65; + target.setAge(realAge); + PerTypeWithinAspectInstanceFactory aif = new PerTypeWithinAspectInstanceFactory(); + TestBean itb = (TestBean) createProxy(target, + getFixture().getAdvisors(aif), + TestBean.class); + assertEquals("No method calls", 0, aif.getInstantiationCount()); + assertEquals("Around advice must now apply", 0, itb.getAge()); + + Advised advised = (Advised) itb; + // Will be ExposeInvocationInterceptor, synthetic instantiation advisor, 2 method advisors + assertEquals(4, advised.getAdvisors().length); + SyntheticInstantiationAdvisor sia = (SyntheticInstantiationAdvisor) advised.getAdvisors()[1]; + assertTrue(sia.getPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null)); + InstantiationModelAwarePointcutAdvisorImpl imapa = (InstantiationModelAwarePointcutAdvisorImpl) advised.getAdvisors()[2]; + LazySingletonAspectInstanceFactoryDecorator maaif = + (LazySingletonAspectInstanceFactoryDecorator) imapa.getAspectInstanceFactory(); + assertTrue(maaif.isMaterialized()); + + // Check that the perclause pointcut is valid + assertTrue(maaif.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null)); + assertNotSame(imapa.getDeclaredPointcut(), imapa.getPointcut()); + + // Hit the method in the per clause to instantiate the aspect + itb.getSpouse(); + + assertTrue(maaif.isMaterialized()); + + assertTrue(imapa.getDeclaredPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getAge"), null)); + + assertEquals("Around advice must still apply", 1, itb.getAge()); + assertEquals("Around advice must still apply", 2, itb.getAge()); + + TestBean itb2 = (TestBean) createProxy(target, + getFixture().getAdvisors(aif), + TestBean.class); + assertEquals(1, aif.getInstantiationCount()); + assertEquals("Around advice be independent for second instance", 0, itb2.getAge()); + assertEquals(2, aif.getInstantiationCount()); + } + + public void testNamedPointcutAspectWithFQN() { + testNamedPointcuts(new NamedPointcutAspectWithFQN()); + } + + public void testNamedPointcutAspectWithoutFQN() { + testNamedPointcuts(new NamedPointcutAspectWithoutFQN()); + } + + public void testNamedPointcutFromAspectLibrary() { + testNamedPointcuts(new NamedPointcutAspectFromLibrary()); + } + + public void testNamedPointcutFromAspectLibraryWithBinding() { + TestBean target = new TestBean(); + ITestBean itb = (ITestBean) createProxy(target, + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new NamedPointcutAspectFromLibraryWithBinding(),"someBean")), + ITestBean.class); + itb.setAge(10); + assertEquals("Around advice must apply", 20, itb.getAge()); + assertEquals(20,target.getAge()); + } + + private void testNamedPointcuts(Object aspectInstance) { + TestBean target = new TestBean(); + int realAge = 65; + target.setAge(realAge); + ITestBean itb = (ITestBean) createProxy(target, + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspectInstance,"someBean")), + ITestBean.class); + assertEquals("Around advice must apply", -1, itb.getAge()); + assertEquals(realAge, target.getAge()); + } + + public void testBindingWithSingleArg() { + TestBean target = new TestBean(); + ITestBean itb = (ITestBean) createProxy(target, + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new BindingAspectWithSingleArg(),"someBean")), + ITestBean.class); + itb.setAge(10); + assertEquals("Around advice must apply", 20, itb.getAge()); + assertEquals(20,target.getAge()); + } + + public void testBindingWithMultipleArgsDifferentlyOrdered() { + ManyValuedArgs target = new ManyValuedArgs(); + ManyValuedArgs mva = (ManyValuedArgs) createProxy(target, + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ManyValuedArgs(),"someBean")), + ManyValuedArgs.class); + + String a = "a"; + int b = 12; + int c = 25; + String d = "d"; + StringBuffer e = new StringBuffer("stringbuf"); + String expectedResult = a + b+ c + d + e; + assertEquals(expectedResult, mva.mungeArgs(a, b, c, d, e)); + } + + /** + * In this case the introduction will be made. + */ + public void testIntroductionOnTargetNotImplementingInterface() { + NotLockable notLockableTarget = new NotLockable(); + assertFalse(notLockableTarget instanceof Lockable); + NotLockable notLockable1 = (NotLockable) createProxy(notLockableTarget, + getFixture().getAdvisors( + new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")), + NotLockable.class); + assertTrue(notLockable1 instanceof Lockable); + Lockable lockable = (Lockable) notLockable1; + assertFalse(lockable.locked()); + lockable.lock(); + assertTrue(lockable.locked()); + + NotLockable notLockable2Target = new NotLockable(); + NotLockable notLockable2 = (NotLockable) createProxy(notLockable2Target, + getFixture().getAdvisors( + new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")), + NotLockable.class); + assertTrue(notLockable2 instanceof Lockable); + Lockable lockable2 = (Lockable) notLockable2; + assertFalse(lockable2.locked()); + notLockable2.setIntValue(1); + lockable2.lock(); + try { + notLockable2.setIntValue(32); + fail(); + } + catch (IllegalStateException ex) { + } + assertTrue(lockable2.locked()); + } + + public void testIntroductionAdvisorExcludedFromTargetImplementingInterface() { + assertTrue(AopUtils.findAdvisorsThatCanApply( + getFixture().getAdvisors( + new SingletonMetadataAwareAspectInstanceFactory( + new MakeLockable(),"someBean")), + CannotBeUnlocked.class).isEmpty()); + assertEquals(2, AopUtils.findAdvisorsThatCanApply(getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")), NotLockable.class).size()); + } + + @SuppressWarnings("unchecked") + public void testIntroductionOnTargetImplementingInterface() { + CannotBeUnlocked target = new CannotBeUnlocked(); + Lockable proxy = (Lockable) createProxy(target, + // Ensure that we exclude + AopUtils.findAdvisorsThatCanApply( + getFixture().getAdvisors( + new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")), + CannotBeUnlocked.class + ), + CannotBeUnlocked.class); + assertTrue(proxy instanceof Lockable); + Lockable lockable = (Lockable) proxy; + assertTrue("Already locked", lockable.locked()); + lockable.lock(); + assertTrue("Real target ignores locking", lockable.locked()); + try { + lockable.unlock(); + fail(); + } + catch (UnsupportedOperationException ex) { + // Ok + } + } + + @SuppressWarnings("unchecked") + public void testIntroductionOnTargetExcludedByTypePattern() { + LinkedList target = new LinkedList(); + List proxy = (List) createProxy(target, + AopUtils.findAdvisorsThatCanApply( + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")), + List.class + ), + CannotBeUnlocked.class); + assertFalse("Type pattern must have excluded mixin", proxy instanceof Lockable); + } + + // TODO: Why does this test fail? It hasn't been run before, so it maybe never actually passed... + public void XtestIntroductionWithArgumentBinding() { + TestBean target = new TestBean(); + + List advisors = getFixture().getAdvisors( + new SingletonMetadataAwareAspectInstanceFactory(new MakeITestBeanModifiable(),"someBean")); + advisors.addAll(getFixture().getAdvisors( + new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean"))); + + Modifiable modifiable = (Modifiable) createProxy(target, + advisors, + ITestBean.class); + assertTrue(modifiable instanceof Modifiable); + Lockable lockable = (Lockable) modifiable; + assertFalse(lockable.locked()); + + ITestBean itb = (ITestBean) modifiable; + assertFalse(modifiable.isModified()); + int oldAge = itb.getAge(); + itb.setAge(oldAge + 1); + assertTrue(modifiable.isModified()); + modifiable.acceptChanges(); + assertFalse(modifiable.isModified()); + itb.setAge(itb.getAge()); + assertFalse("Setting same value does not modify", modifiable.isModified()); + itb.setName("And now for something completely different"); + assertTrue(modifiable.isModified()); + + lockable.lock(); + assertTrue(lockable.locked()); + try { + itb.setName("Else"); + fail("Should be locked"); + } + catch (IllegalStateException ex) { + // Ok + } + lockable.unlock(); + itb.setName("Tony"); + } + + public void testAspectMethodThrowsExceptionLegalOnSignature() { + TestBean target = new TestBean(); + UnsupportedOperationException expectedException = new UnsupportedOperationException(); + List advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException),"someBean")); + assertEquals("One advice method was found", 1, advisors.size()); + ITestBean itb = (ITestBean) createProxy(target, + advisors, + ITestBean.class); + try { + itb.getAge(); + fail(); + } + catch (UnsupportedOperationException ex) { + assertSame(expectedException, ex); + } + } + + // TODO document this behaviour. + // Is it different AspectJ behaviour, at least for checked exceptions? + public void testAspectMethodThrowsExceptionIllegalOnSignature() { + TestBean target = new TestBean(); + RemoteException expectedException = new RemoteException(); + List advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException),"someBean")); + assertEquals("One advice method was found", 1, advisors.size()); + ITestBean itb = (ITestBean) createProxy(target, + advisors, + ITestBean.class); + try { + itb.getAge(); + fail(); + } + catch (UndeclaredThrowableException ex) { + assertSame(expectedException, ex.getCause()); + } + } + + protected Object createProxy(Object target, List advisors, Class ... interfaces) { + ProxyFactory pf = new ProxyFactory(target); + if (interfaces.length > 1 || interfaces[0].isInterface()) { + pf.setInterfaces(interfaces); + } + else { + pf.setProxyTargetClass(true); + } + + // Required everywhere we use AspectJ proxies + pf.addAdvice(ExposeInvocationInterceptor.INSTANCE); + + for (Object a : advisors) { + pf.addAdvisor((Advisor) a); + } + + pf.setExposeProxy(true); + return pf.getProxy(); + } + + public void testTwoAdvicesOnOneAspect() { + TestBean target = new TestBean(); + + TwoAdviceAspect twoAdviceAspect = new TwoAdviceAspect(); + List advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(twoAdviceAspect,"someBean")); + assertEquals("Two advice methods found", 2, advisors.size()); + ITestBean itb = (ITestBean) createProxy(target, + advisors, + ITestBean.class); + itb.setName(""); + assertEquals(0, itb.getAge()); + int newAge = 32; + itb.setAge(newAge); + assertEquals(1, itb.getAge()); + } + + public void testAfterAdviceTypes() throws Exception { + Echo target = new Echo(); + + ExceptionHandling afterReturningAspect = new ExceptionHandling(); + List advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(afterReturningAspect,"someBean")); + Echo echo = (Echo) createProxy(target, + advisors, + Echo.class); + assertEquals(0, afterReturningAspect.successCount); + assertEquals("", echo.echo("")); + assertEquals(1, afterReturningAspect.successCount); + assertEquals(0, afterReturningAspect.failureCount); + try { + echo.echo(new ServletException()); + fail(); + } + catch (ServletException ex) { + // Ok + } + catch (Exception ex) { + fail(); + } + assertEquals(1, afterReturningAspect.successCount); + assertEquals(1, afterReturningAspect.failureCount); + assertEquals(afterReturningAspect.failureCount + afterReturningAspect.successCount, afterReturningAspect.afterCount); + } + + public void testFailureWithoutExplicitDeclarePrecedence() { + TestBean target = new TestBean(); + ITestBean itb = (ITestBean) createProxy(target, + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new NoDeclarePrecedenceShouldFail(), "someBean")), + ITestBean.class); + try { + itb.getAge(); + fail(); + } + catch (IllegalStateException ex) { + // expected + } + } + + public void testDeclarePrecedenceNotSupported() { + TestBean target = new TestBean(); + try { + createProxy(target, + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory( + new DeclarePrecedenceShouldSucceed(),"someBean")), + ITestBean.class); + fail(); + } + catch (IllegalArgumentException ex) { + // Not supported in 2.0 + } + } + + /** Not supported in 2.0! + public void testExplicitDeclarePrecedencePreventsFailure() { + TestBean target = new TestBean(); + ITestBean itb = (ITestBean) createProxy(target, + getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new DeclarePrecedenceShouldSucceed(), "someBean")), + ITestBean.class); + assertEquals(666, itb.getAge()); + } + */ + + + @Aspect("percflow(execution(* *(..)))") + public static class PerCflowAspect { + } + + + @Aspect("percflowbelow(execution(* *(..)))") + public static class PerCflowBelowAspect { + } + + + @Aspect("pertarget(execution(* *.getSpouse()))") + public static class PerTargetAspect implements Ordered { + + public int count; + + private int order = Ordered.LOWEST_PRECEDENCE; + + @Around("execution(int *.getAge())") + public int returnCountAsAge() { + return count++; + } + + @Before("execution(void *.set*(int))") + public void countSetter() { + ++count; + } + + public int getOrder() { + return this.order; + } + + public void setOrder(int order) { + this.order = order; + } + } + + + @Aspect("pertarget(execution(* *.getSpouse()))") + @Order(10) + public static class PerTargetAspectWithOrderAnnotation10 { + + public int count; + + @Around("execution(int *.getAge())") + public int returnCountAsAge() { + return count++; + } + + @Before("execution(void *.set*(int))") + public void countSetter() { + ++count; + } + } + + + @Aspect("pertarget(execution(* *.getSpouse()))") + @Order(5) + public static class PerTargetAspectWithOrderAnnotation5 { + + public int count; + + @Around("execution(int *.getAge())") + public int returnCountAsAge() { + return count++; + } + + @Before("execution(void *.set*(int))") + public void countSetter() { + ++count; + } + } + + + @Aspect("perthis(execution(* *.getSpouse()))") + public static class PerThisAspect { + + public int count; + + /** + * Just to check that this doesn't cause problems with introduction processing + */ + private ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean(); + + @Around("execution(int *.getAge())") + public int returnCountAsAge() { + return count++; + } + + @Before("execution(void *.set*(int))") + public void countSetter() { + ++count; + } + } + + + @Aspect("pertypewithin(org.springframework.beans.IOther+)") + public static class PerTypeWithinAspect { + + public int count; + + @Around("execution(int *.getAge())") + public int returnCountAsAge() { + return count++; + } + + @Before("execution(void *.*(..))") + public void countAnythingVoid() { + ++count; + } + } + + + private class PerTypeWithinAspectInstanceFactory implements MetadataAwareAspectInstanceFactory { + + private int count; + + public int getInstantiationCount() { + return this.count; + } + + public Object getAspectInstance() { + ++this.count; + return new PerTypeWithinAspect(); + } + + public ClassLoader getAspectClassLoader() { + return PerTypeWithinAspect.class.getClassLoader(); + } + + public AspectMetadata getAspectMetadata() { + return new AspectMetadata(PerTypeWithinAspect.class, "perTypeWithin"); + } + + public int getOrder() { + return Ordered.LOWEST_PRECEDENCE; + } + } + + + @Aspect + public static class NamedPointcutAspectWithFQN { + + @SuppressWarnings("unused") + private ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean(); + + @Pointcut("execution(* getAge())") + public void getAge() { + } + + @Around("org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.NamedPointcutAspectWithFQN.getAge()") + public int changeReturnValue(ProceedingJoinPoint pjp) { + return -1; + } + } + + + @Aspect + public static class NamedPointcutAspectWithoutFQN { + @Pointcut("execution(* getAge())") + public void getAge() { + } + + @Around("getAge()") + public int changeReturnValue(ProceedingJoinPoint pjp) { + return -1; + } + } + + + @Aspect + public static class NamedPointcutAspectFromLibrary { + + @Around("org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.propertyAccess()") + public int changeReturnType(ProceedingJoinPoint pjp) { + return -1; + } + + @Around(value="org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.integerArgOperation(x)", argNames="x") + public void doubleArg(ProceedingJoinPoint pjp, int x) throws Throwable { + pjp.proceed(new Object[] {x*2}); + } + } + + + @Aspect + public static class Library { + + @Pointcut("execution(!void get*())") + public void propertyAccess() {} + + @Pointcut("execution(* *(..)) && args(i)") + public void integerArgOperation(int i) {} + + } + + + @Aspect + public static class NamedPointcutAspectFromLibraryWithBinding { + + @Around(value="org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.integerArgOperation(x)", argNames="x") + public void doubleArg(ProceedingJoinPoint pjp, int x) throws Throwable { + pjp.proceed(new Object[] {x*2}); + } + } + + + @Aspect + public static class BindingAspectWithSingleArg { + + @Pointcut(value="args(a)", argNames="a") + public void setAge(int a) {} + + @Around(value="setAge(age)",argNames="age") + // @ArgNames({"age"}) // AMC needs more work here? ignoring pjp arg... ok?? + // // argNames should be suported in Around as it is in Pointcut + public void changeReturnType(ProceedingJoinPoint pjp, int age) throws Throwable { + pjp.proceed(new Object[] {age*2}); + } + } + + + @Aspect + public static class ManyValuedArgs { + public String mungeArgs(String a, int b, int c, String d, StringBuffer e) { + return a + b + c + d + e; + } + + @Around(value="execution(String mungeArgs(..)) && args(a, b, c, d, e)", + argNames="b,c,d,e,a") + public String reverseAdvice(ProceedingJoinPoint pjp, int b, int c, String d, StringBuffer e, String a) throws Throwable { + assertEquals(a + b+ c+ d+ e, pjp.proceed()); + return a + b + c + d + e; + } + } + + + @Aspect + public static class ExceptionAspect { + private final Exception ex; + + public ExceptionAspect(Exception ex) { + this.ex = ex; + } + + @Before("execution(* getAge())") + public void throwException() throws Exception { + throw ex; + } + } + + + @Aspect + public static class TwoAdviceAspect { + private int totalCalls; + + @Around("execution(* getAge())") + public int returnCallCount(ProceedingJoinPoint pjp) throws Exception { + return totalCalls; + } + + @Before("execution(* setAge(int)) && args(newAge)") + public void countSet(int newAge) throws Exception { + ++totalCalls; + } + } + + + public static class Echo { + + public Object echo(Object o) throws Exception { + if (o instanceof Exception) { + throw (Exception) o; + } + return o; + } + } + + + @Aspect + public static class ExceptionHandling { + public int successCount; + public int failureCount; + public int afterCount; + + @AfterReturning("execution(* echo(*))") + public void succeeded() { + ++successCount; + } + + @AfterThrowing("execution(* echo(*))") + public void failed() { + ++failureCount; + } + + @After("execution(* echo(*))") + public void invoked() { + ++afterCount; + } + } + + + @Aspect + public static class NoDeclarePrecedenceShouldFail { + + @Pointcut("execution(int *.getAge())") + public void getAge() { + } + + @Before("getAge()") + public void blowUpButDoesntMatterBecauseAroundAdviceWontLetThisBeInvoked() { + throw new IllegalStateException(); + } + + @Around("getAge()") + public int preventExecution(ProceedingJoinPoint pjp) { + return 666; + } + } + + + @Aspect + @DeclarePrecedence("org.springframework..*") + public static class DeclarePrecedenceShouldSucceed { + + @Pointcut("execution(int *.getAge())") + public void getAge() { + } + + @Before("getAge()") + public void blowUpButDoesntMatterBecauseAroundAdviceWontLetThisBeInvoked() { + throw new IllegalStateException(); + } + + @Around("getAge()") + public int preventExecution(ProceedingJoinPoint pjp) { + return 666; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AbstractMakeModifiable.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AbstractMakeModifiable.java new file mode 100644 index 00000000000..bae85794d94 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AbstractMakeModifiable.java @@ -0,0 +1,109 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.annotation; + +import java.lang.reflect.Method; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.reflect.MethodSignature; + +import org.springframework.util.ObjectUtils; + +/** + * Add a DeclareParents field in concrete subclasses, to identify + * the type pattern to apply the introduction to. + * + * @author Rod Johnson + * @since 2.0 + */ +@Aspect +public abstract class AbstractMakeModifiable { + + public interface MutableModifable extends Modifiable { + void markDirty(); + } + + public static class ModifiableImpl implements MutableModifable { + private boolean modified; + + public void acceptChanges() { + modified = false; + } + + public boolean isModified() { + return modified; + } + + public void markDirty() { + this.modified = true; + } + } + + @Before(value="execution(void set*(*)) && this(modifiable) && args(newValue)", + argNames="modifiable,newValue") + public void recordModificationIfSetterArgumentDiffersFromOldValue(JoinPoint jp, + MutableModifable mixin, Object newValue) { + + /* + * We use the mixin to check and, if necessary, change, + * modification status. We need the JoinPoint to get the + * setter method. We use newValue for comparison. + * We try to invoke the getter if possible. + */ + + if (mixin.isModified()) { + // Already changed, don't need to change again + //System.out.println("changed"); + return; + } + + // Find the current raw value, by invoking the corresponding setter + Method correspondingGetter = getGetterFromSetter(((MethodSignature) jp.getSignature()).getMethod()); + boolean modified = true; + if (correspondingGetter != null) { + try { + Object oldValue = correspondingGetter.invoke(jp.getTarget()); + //System.out.println("Old value=" + oldValue + "; new=" + newValue); + modified = !ObjectUtils.nullSafeEquals(oldValue, newValue); + } + catch (Exception ex) { + ex.printStackTrace(); + // Don't sweat on exceptions; assume value was modified + } + } + else { + //System.out.println("cannot get getter for " + jp); + } + if (modified) { + mixin.markDirty(); + } + } + + private Method getGetterFromSetter(Method setter) { + String getterName = setter.getName().replaceFirst("set", "get"); + try { + return setter.getDeclaringClass().getMethod(getterName, (Class[]) null); + } + catch (NoSuchMethodException ex) { + // must be write only + return null; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/ArgumentBindingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/ArgumentBindingTests.java new file mode 100644 index 00000000000..4f53faaf70b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/ArgumentBindingTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.annotation; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.test.AssertThrows; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author Adrian Colyer + * @author Juergen Hoeller + */ +public class ArgumentBindingTests extends TestCase { + + public void testBindingInPointcutUsedByAdvice() { + TestBean tb = new TestBean(); + AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb); + proxyFactory.addAspect(NamedPointcutWithArgs.class); + final ITestBean proxiedTestBean = (ITestBean) proxyFactory.getProxy(); + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + proxiedTestBean.setName("Supercalifragalisticexpialidocious"); + } + }.runTest(); + } + + public void testAnnotationArgumentNameBinding() { + TransactionalBean tb = new TransactionalBean(); + AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb); + proxyFactory.addAspect(PointcutWithAnnotationArgument.class); + final ITransactionalBean proxiedTestBean = (ITransactionalBean) proxyFactory.getProxy(); + new AssertThrows(IllegalStateException.class) { + public void test() throws Exception { + proxiedTestBean.doInTransaction(); + } + }.runTest(); + } + + public void testParameterNameDiscoverWithReferencePointcut() throws Exception { + AspectJAdviceParameterNameDiscoverer discoverer = + new AspectJAdviceParameterNameDiscoverer("somepc(formal) && set(* *)"); + discoverer.setRaiseExceptions(true); + Method methodUsedForParameterTypeDiscovery = + getClass().getMethod("methodWithOneParam", String.class); + String[] pnames = discoverer.getParameterNames(methodUsedForParameterTypeDiscovery); + assertEquals("one parameter name", 1, pnames.length); + assertEquals("formal", pnames[0]); + } + + public void methodWithOneParam(String aParam) { + } + + + public interface ITransactionalBean { + + @Transactional + void doInTransaction(); + } + + + public static class TransactionalBean implements ITransactionalBean { + + @Transactional + public void doInTransaction() { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectJAdviceParameterNameDiscoverAnnotationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectJAdviceParameterNameDiscoverAnnotationTests.java new file mode 100644 index 00000000000..4b5048421d3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectJAdviceParameterNameDiscoverAnnotationTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import org.aspectj.lang.ProceedingJoinPoint; + +import org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscovererTests; + +/** + * Additional parameter name discover tests that need Java 5. + * Yes this will re-run the tests from the superclass, but that + * doesn't matter in the grand scheme of things... + * + * @author Adrian Colyer + */ +public class AspectJAdviceParameterNameDiscoverAnnotationTests extends AspectJAdviceParameterNameDiscovererTests { + + @Retention(RetentionPolicy.RUNTIME) + @interface MyAnnotation {} + + public void pjpAndAnAnnotation(ProceedingJoinPoint pjp, MyAnnotation ann) {} + + public void testAnnotationBinding() { + assertParameterNames(getMethod("pjpAndAnAnnotation"), + "execution(* *(..)) && @annotation(ann)", + new String[] {"thisJoinPoint","ann"}); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectJPointcutAdvisorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectJPointcutAdvisorTests.java new file mode 100644 index 00000000000..c158ebcbe1e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectJPointcutAdvisorTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.annotation; + +import junit.framework.TestCase; + +import org.springframework.aop.Pointcut; +import org.springframework.aop.aspectj.AspectJExpressionPointcut; +import org.springframework.aop.aspectj.AspectJExpressionPointcutTests; +import org.springframework.aop.framework.AopConfigException; +import org.springframework.beans.TestBean; + +/** + * @author Rod Johnson + */ +public class AspectJPointcutAdvisorTests extends TestCase { + + private AspectJAdvisorFactory af = new ReflectiveAspectJAdvisorFactory(); + + public void testSingleton() throws SecurityException, NoSuchMethodException { + AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(); + ajexp.setExpression(AspectJExpressionPointcutTests.MATCH_ALL_METHODS); + + InstantiationModelAwarePointcutAdvisorImpl ajpa = new InstantiationModelAwarePointcutAdvisorImpl(af, ajexp, + new SingletonMetadataAwareAspectInstanceFactory(new AbstractAspectJAdvisorFactoryTests.ExceptionAspect(null),"someBean"), + TestBean.class.getMethod("getAge", (Class[]) null),1,"someBean"); + assertSame(Pointcut.TRUE, ajpa.getAspectMetadata().getPerClausePointcut()); + assertFalse(ajpa.isPerInstance()); + } + + public void testPerTarget() throws SecurityException, NoSuchMethodException { + AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(); + ajexp.setExpression(AspectJExpressionPointcutTests.MATCH_ALL_METHODS); + + InstantiationModelAwarePointcutAdvisorImpl ajpa = new InstantiationModelAwarePointcutAdvisorImpl(af, ajexp, + new SingletonMetadataAwareAspectInstanceFactory(new AbstractAspectJAdvisorFactoryTests.PerTargetAspect(),"someBean"), null, 1, "someBean"); + assertNotSame(Pointcut.TRUE, ajpa.getAspectMetadata().getPerClausePointcut()); + assertTrue(ajpa.getAspectMetadata().getPerClausePointcut() instanceof AspectJExpressionPointcut); + assertTrue(ajpa.isPerInstance()); + + assertTrue(ajpa.getAspectMetadata().getPerClausePointcut().getClassFilter().matches(TestBean.class)); + assertFalse(ajpa.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches( + TestBean.class.getMethod("getAge", (Class[]) null), + TestBean.class)); + + assertTrue(ajpa.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches( + TestBean.class.getMethod("getSpouse", (Class[]) null), + TestBean.class)); + } + + + public void testPerCflowTarget() { + testIllegalInstantiationModel(AbstractAspectJAdvisorFactoryTests.PerCflowAspect.class); + } + + public void testPerCflowBelowTarget() { + testIllegalInstantiationModel(AbstractAspectJAdvisorFactoryTests.PerCflowBelowAspect.class); + } + + private void testIllegalInstantiationModel(Class c) { + try { + new AspectMetadata(c,"someBean"); + fail(); + } + catch (AopConfigException ex) { + // OK + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectMetadataTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectMetadataTests.java new file mode 100644 index 00000000000..f6e3b04096f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectMetadataTests.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2005 the original author 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.aop.aspectj.annotation; + +import junit.framework.TestCase; +import org.aspectj.lang.reflect.PerClauseKind; + +import org.springframework.aop.Pointcut; +import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.ExceptionAspect; +import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.PerTargetAspect; +import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.PerThisAspect; + +/** + * + * @since 2.0 + * @author Rod Johnson + * + */ +public class AspectMetadataTests extends TestCase { + + public void testNotAnAspect() { + try { + new AspectMetadata(String.class,"someBean"); + fail(); + } + catch (IllegalArgumentException ex) { + // Ok + } + } + + public void testSingletonAspect() { + AspectMetadata am = new AspectMetadata(ExceptionAspect.class,"someBean"); + assertFalse(am.isPerThisOrPerTarget()); + assertSame(Pointcut.TRUE, am.getPerClausePointcut()); + assertEquals(PerClauseKind.SINGLETON, am.getAjType().getPerClause().getKind()); + } + + public void testPerTargetAspect() { + AspectMetadata am = new AspectMetadata(PerTargetAspect.class,"someBean"); + assertTrue(am.isPerThisOrPerTarget()); + assertNotSame(Pointcut.TRUE, am.getPerClausePointcut()); + assertEquals(PerClauseKind.PERTARGET, am.getAjType().getPerClause().getKind()); + } + + public void testPerThisAspect() { + AspectMetadata am = new AspectMetadata(PerThisAspect.class,"someBean"); + assertTrue(am.isPerThisOrPerTarget()); + assertNotSame(Pointcut.TRUE, am.getPerClausePointcut()); + assertEquals(PerClauseKind.PERTHIS, am.getAjType().getPerClause().getKind()); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectProxyFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectProxyFactoryTests.java new file mode 100644 index 00000000000..8bf7fc8eede --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/AspectProxyFactoryTests.java @@ -0,0 +1,122 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.annotation; + +import junit.framework.TestCase; + +import org.springframework.aop.aspectj.autoproxy.MultiplyReturnValue; +import org.springframework.aop.aspectj.autoproxy.PerThisAspect; +import org.springframework.test.AssertThrows; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class AspectProxyFactoryTests extends TestCase { + + public void testWithNonAspect() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean()); + proxyFactory.addAspect(TestBean.class); + } + }.runTest(); + } + + public void testWithSimpleAspect() throws Exception { + TestBean bean = new TestBean(); + bean.setAge(2); + AspectJProxyFactory proxyFactory = new AspectJProxyFactory(bean); + proxyFactory.addAspect(MultiplyReturnValue.class); + ITestBean proxy = proxyFactory.getProxy(); + assertEquals("Multiplication did not occur", bean.getAge() * 2, proxy.getAge()); + } + + public void testWithPerThisAspect() throws Exception { + TestBean bean1 = new TestBean(); + TestBean bean2 = new TestBean(); + + AspectJProxyFactory pf1 = new AspectJProxyFactory(bean1); + pf1.addAspect(PerThisAspect.class); + + AspectJProxyFactory pf2 = new AspectJProxyFactory(bean2); + pf2.addAspect(PerThisAspect.class); + + ITestBean proxy1 = pf1.getProxy(); + ITestBean proxy2 = pf2.getProxy(); + + assertEquals(0, proxy1.getAge()); + assertEquals(1, proxy1.getAge()); + assertEquals(0, proxy2.getAge()); + assertEquals(2, proxy1.getAge()); + } + + public void testWithInstanceWithNonAspect() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + AspectJProxyFactory pf = new AspectJProxyFactory(); + pf.addAspect(new TestBean()); + } + }.runTest(); + } + + public void testWithInstance() throws Exception { + MultiplyReturnValue aspect = new MultiplyReturnValue(); + int multiple = 3; + aspect.setMultiple(multiple); + + TestBean target = new TestBean(); + target.setAge(24); + + AspectJProxyFactory proxyFactory = new AspectJProxyFactory(target); + proxyFactory.addAspect(aspect); + + ITestBean proxy = proxyFactory.getProxy(); + + assertEquals(target.getAge() * multiple, proxy.getAge()); + } + + public void testWithNonSingletonAspectInstance() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + AspectJProxyFactory pf = new AspectJProxyFactory(); + pf.addAspect(new PerThisAspect()); + } + }.runTest(); + } + + + public static interface ITestBean { + + int getAge(); + } + + + public static class TestBean implements ITestBean { + + private int age; + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/CannotBeUnlocked.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/CannotBeUnlocked.java new file mode 100644 index 00000000000..fa63675b71e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/CannotBeUnlocked.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2005 the original author 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.aop.aspectj.annotation; + +import org.springframework.aop.framework.Lockable; + +/** + * + * + * @author Rod Johnson + * + */ +public class CannotBeUnlocked implements Lockable, Comparable { + + public void lock() { + } + + public void unlock() { + throw new UnsupportedOperationException(); + } + + public boolean locked() { + return true; + } + + public int compareTo(Object arg0) { + throw new UnsupportedOperationException(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/FooAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/FooAspect.java new file mode 100644 index 00000000000..04db891a7df --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/FooAspect.java @@ -0,0 +1,28 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.annotation; + +import org.aspectj.lang.annotation.Aspect; + +/** + * @author Rob Harrop + * @since 2.o + */ +@Aspect +public class FooAspect { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/MakeITestBeanModifiable.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/MakeITestBeanModifiable.java new file mode 100644 index 00000000000..58bc09c9f6c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/MakeITestBeanModifiable.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.annotation; + +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.DeclareParents; + +/** + * Adds a declare parents pointcut. + * @author Rod Johnson + * @since 2.0 + */ +@Aspect +public class MakeITestBeanModifiable extends AbstractMakeModifiable { + + @DeclareParents(value = "org.springframework.beans.ITestBean+", + defaultImpl=ModifiableImpl.class) + public static MutableModifable mixin; + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/MakeLockable.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/MakeLockable.java new file mode 100644 index 00000000000..071be326c74 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/MakeLockable.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.annotation; + +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.DeclareParents; +import org.springframework.aop.framework.DefaultLockable; +import org.springframework.aop.framework.Lockable; + +/** + * Demonstrates introductions, AspectJ annotation style. + *

+ * @author Rod Johnson + * @since 2.0 + */ +@Aspect +public class MakeLockable { + + @DeclareParents(value = "org.springframework..*", + defaultImpl=DefaultLockable.class) + public static Lockable mixin; + + @Before(value="execution(void set*(*)) && this(mixin)", argNames="mixin") + public void checkNotLocked( + Lockable mixin) // Bind to arg + { + // Can also obtain the mixin (this) this way + //Lockable mixin = (Lockable) jp.getThis(); + if (mixin.locked()) { + throw new IllegalStateException(); + } + } + +} + +/* + * + * public aspect MakeLockable { + * + * declare parents org....* implements Lockable; + * + * private boolean Lockable.locked; + + * public void Lockable.lock() { + this.locked = true; + } + + * public void Lockable.unlock() { + this.locked = false; + } + + * public boolean Lockable.locked() { + return this.locked; + } + * + * + * } + */ diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/Modifiable.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/Modifiable.java new file mode 100644 index 00000000000..1bdfe67fe5a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/Modifiable.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.annotation; + +/** + * Used as a mixin. + * + * @author Rod Johnson + */ +public interface Modifiable { + + boolean isModified(); + + void acceptChanges(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/NamedPointcutWithArgs.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/NamedPointcutWithArgs.java new file mode 100644 index 00000000000..8f80a5644c2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/NamedPointcutWithArgs.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.annotation; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; + +/** + * @author Adrian Colyer + */ +@Aspect +public class NamedPointcutWithArgs { + + @Pointcut("execution(* *(..)) && args(s,..)") + public void pointcutWithArgs(String s) {} + + @Around("pointcutWithArgs(aString)") + public Object doAround(ProceedingJoinPoint pjp, String aString) throws Throwable { + System.out.println("got '" + aString + "' at '" + pjp + "'"); + throw new IllegalArgumentException(aString); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/NotLockable.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/NotLockable.java new file mode 100644 index 00000000000..928e006f182 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/NotLockable.java @@ -0,0 +1,15 @@ +package org.springframework.aop.aspectj.annotation; + +public class NotLockable { + + private int intValue; + + public int getIntValue() { + return intValue; + } + + public void setIntValue(int intValue) { + this.intValue = intValue; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/PointcutWithAnnotationArgument.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/PointcutWithAnnotationArgument.java new file mode 100644 index 00000000000..7996374ffa5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/PointcutWithAnnotationArgument.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.annotation; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +import org.springframework.transaction.annotation.Transactional; + +/** + * @author Juergen Hoeller + */ +@Aspect +public class PointcutWithAnnotationArgument { + + @Around(value = "execution(* org.springframework..*.*(..)) && @annotation(transaction)") + public Object around(ProceedingJoinPoint pjp, Transactional transaction) throws Throwable { + System.out.println("Invoked with transaction " + transaction); + throw new IllegalStateException(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactoryTests.java new file mode 100644 index 00000000000..45a12e4e9a8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactoryTests.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.annotation; + +/** + * Tests for ReflectiveAtAspectJAdvisorFactory. + * Tests are inherited: we only set the test fixture here. + * + * @author Rod Johnson + * @since 2.0 + */ +public class ReflectiveAspectJAdvisorFactoryTests extends AbstractAspectJAdvisorFactoryTests { + + @Override + protected AspectJAdvisorFactory getFixture() { + return new ReflectiveAspectJAdvisorFactory(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AdviceUsingThisJoinPoint.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AdviceUsingThisJoinPoint.java new file mode 100644 index 00000000000..d53ec278a07 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AdviceUsingThisJoinPoint.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2005 the original author 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.aop.aspectj.autoproxy; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; + +@Aspect +public class AdviceUsingThisJoinPoint { + + private String lastEntry = ""; + + public String getLastMethodEntered() { + return this.lastEntry; + } + + @Pointcut("execution(* *(..))") + public void methodExecution() {} + + @Before("methodExecution()") + public void entryTrace(JoinPoint jp) { + this.lastEntry = jp.toString(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotatedTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotatedTestBean.java new file mode 100644 index 00000000000..85506559731 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotatedTestBean.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +/** + * @author Adrian Colyer + * @since 2.0 + */ +public interface AnnotatedTestBean { + + String doThis(); + + String doThat(); + + String doTheOther(); + + String[] doArray(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotatedTestBeanImpl.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotatedTestBeanImpl.java new file mode 100644 index 00000000000..00a47ff1a20 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotatedTestBeanImpl.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import org.springframework.transaction.annotation.Transactional; + +/** + * @author Adrian Colyer + * @since 2.0 + */ +@Transactional +public class AnnotatedTestBeanImpl implements AnnotatedTestBean { + + @TestAnnotation("this value") + public String doThis() { + return "doThis"; + } + + @TestAnnotation("that value") + public String doThat() { + return "doThat"; + } + + @TestAnnotation("array value") + public String[] doArray() { + return new String[] {"doThis", "doThat"}; + } + + // not annotated + public String doTheOther() { + return "doTheOther"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationBindingTestAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationBindingTestAspect.java new file mode 100644 index 00000000000..ba74b1a7a4b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationBindingTestAspect.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import org.aspectj.lang.ProceedingJoinPoint; + +/** + * @author Adrian Colyer + */ +public class AnnotationBindingTestAspect { + + public String doWithAnnotation(ProceedingJoinPoint pjp, TestAnnotation testAnnotation) throws Throwable { + return testAnnotation.value(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationBindingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationBindingTests.java new file mode 100644 index 00000000000..9487fd7132f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationBindingTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Adrian Colyer + */ +public class AnnotationBindingTests extends AbstractDependencyInjectionSpringContextTests { + + private AnnotatedTestBean testBean; + + @Override + protected String getConfigPath() { + return "around-advice-tests.xml"; + } + + public void setTestBean(AnnotatedTestBean testBean) { + this.testBean = testBean; + } + + public void testAnnotationBindingInAroundAdvice() { + assertEquals("this value", testBean.doThis()); + assertEquals("that value", testBean.doThat()); + } + + public void testNoMatchingWithoutAnnotationPresent() { + assertEquals("doTheOther", testBean.doTheOther()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationPointcutTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationPointcutTests.java new file mode 100644 index 00000000000..a894b8f9536 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationPointcutTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Juergen Hoeller + */ +public class AnnotationPointcutTests extends AbstractDependencyInjectionSpringContextTests { + + private AnnotatedTestBean testBean; + + @Override + protected String getConfigPath() { + return "annotationPointcut.xml"; + } + + public void setTestBean(AnnotatedTestBean testBean) { + this.testBean = testBean; + } + + public void testAnnotationBindingInAroundAdvice() { + assertEquals("this value", testBean.doThis()); + } + + public void testNoMatchingWithoutAnnotationPresent() { + assertEquals("doTheOther", testBean.doTheOther()); + } + + + public static class TestMethodInterceptor implements MethodInterceptor { + + public Object invoke(MethodInvocation methodInvocation) throws Throwable { + return "this value"; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJAutoProxyCreatorAndLazyInitTargetSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJAutoProxyCreatorAndLazyInitTargetSourceTests.java new file mode 100644 index 00000000000..760d10849c2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJAutoProxyCreatorAndLazyInitTargetSourceTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import org.springframework.beans.ITestBean; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Rod Johnson + * @author Rob Harrop + */ +public class AspectJAutoProxyCreatorAndLazyInitTargetSourceTests extends AbstractDependencyInjectionSpringContextTests { + + public AspectJAutoProxyCreatorAndLazyInitTargetSourceTests() { + setAutowireMode(AUTOWIRE_BY_NAME); + } + + @Override + protected String getConfigPath() { + return "lazy.xml"; + } + + public void testAdrian() { + ITestBean adrian = (ITestBean) applicationContext.getBean("adrian"); + assertEquals(0, LazyTestBean.instantiations); + assertNotNull(adrian); + adrian.getAge(); + assertEquals(68, adrian.getAge()); + assertEquals(1, LazyTestBean.instantiations); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJAutoProxyCreatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJAutoProxyCreatorTests.java new file mode 100644 index 00000000000..c22acd5be26 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJAutoProxyCreatorTests.java @@ -0,0 +1,319 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import junit.framework.TestCase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests; +import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator; +import org.springframework.aop.aspectj.annotation.AspectMetadata; +import org.springframework.aop.config.AopConfigUtils; +import org.springframework.aop.framework.ProxyConfig; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.INestedTestBean; +import org.springframework.beans.ITestBean; +import org.springframework.beans.NestedTestBean; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.config.MethodInvokingFactoryBean; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.util.StopWatch; + +/** + * Tests for AspectJ auto-proxying. Includes mixing with Spring AOP Advisors + * to demonstrate that existing autoproxying contract is honoured. + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class AspectJAutoProxyCreatorTests extends TestCase { + + private static final Log factoryLog = LogFactory.getLog(DefaultListableBeanFactory.class); + + public void testAspectsAreApplied() { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/aspects.xml"); + ITestBean tb = (ITestBean) bf.getBean("adrian"); + assertEquals(68, tb.getAge()); + MethodInvokingFactoryBean factoryBean = (MethodInvokingFactoryBean) bf.getBean("&factoryBean"); + assertTrue(AopUtils.isAopProxy(factoryBean.getTargetObject())); + assertEquals(68, ((ITestBean) factoryBean.getTargetObject()).getAge()); + } + + public void testMultipleAspectsWithParameterApplied() { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/aspects.xml"); + ITestBean tb = (ITestBean) bf.getBean("adrian"); + tb.setAge(10); + assertEquals(20, tb.getAge()); + } + + public void testAspectsAreAppliedInDefinedOrder() { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/aspectsWithOrdering.xml"); + ITestBean tb = (ITestBean) bf.getBean("adrian"); + assertEquals(71, tb.getAge()); + } + + public void testAspectsAndAdvisorAreApplied() { + ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/aspectsPlusAdvisor.xml"); + ITestBean shouldBeWeaved = (ITestBean) ac.getBean("adrian"); + testAspectsAndAdvisorAreApplied(ac, shouldBeWeaved); + } + + public void testAspectsAndAdvisorAppliedToPrototypeIsFastEnough() { + if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/aspectsPlusAdvisor.xml"); + StopWatch sw = new StopWatch(); + sw.start("prototype"); + for (int i = 0; i < 10000; i++) { + ITestBean shouldBeWeaved = (ITestBean) ac.getBean("adrian2"); + if (i < 10) { + testAspectsAndAdvisorAreApplied(ac, shouldBeWeaved); + } + } + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 4000); + } + + public void testAspectsAndAdvisorNotAppliedToPrototypeIsFastEnough() { + if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/aspectsPlusAdvisor.xml"); + StopWatch sw = new StopWatch(); + sw.start("prototype"); + for (int i = 0; i < 100000; i++) { + INestedTestBean shouldNotBeWeaved = (INestedTestBean) ac.getBean("i21"); + if (i < 10) { + assertFalse(AopUtils.isAopProxy(shouldNotBeWeaved)); + } + } + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 3000); + } + + public void testAspectsAndAdvisorNotAppliedToManySingletonsIsFastEnough() { + if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + GenericApplicationContext ac = new GenericApplicationContext(); + new XmlBeanDefinitionReader(ac).loadBeanDefinitions( + "/org/springframework/aop/aspectj/autoproxy/aspectsPlusAdvisor.xml"); + for (int i = 0; i < 10000; i++) { + ac.registerBeanDefinition("singleton" + i, new RootBeanDefinition(NestedTestBean.class)); + } + StopWatch sw = new StopWatch(); + sw.start("singleton"); + ac.refresh(); + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("Singleton creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 4000); + } + + public void testAspectsAndAdvisorAreAppliedEvenIfComingFromParentFactory() { + ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/aspectsPlusAdvisor.xml"); + GenericApplicationContext childAc = new GenericApplicationContext(ac); + // Create a child factory with a bean that should be weaved + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); + bd.getPropertyValues().addPropertyValue(new PropertyValue("name", "Adrian")). + addPropertyValue(new PropertyValue("age", new Integer(34))); + childAc.registerBeanDefinition("adrian2", bd); + // Register the advisor auto proxy creator with subclass + childAc.registerBeanDefinition(AnnotationAwareAspectJAutoProxyCreator.class.getName(), + new RootBeanDefinition(AnnotationAwareAspectJAutoProxyCreator.class)); + childAc.refresh(); + + ITestBean beanFromChildContextThatShouldBeWeaved = (ITestBean) childAc.getBean("adrian2"); + //testAspectsAndAdvisorAreApplied(childAc, (ITestBean) ac.getBean("adrian")); + testAspectsAndAdvisorAreApplied(childAc, beanFromChildContextThatShouldBeWeaved); + } + + protected void testAspectsAndAdvisorAreApplied(ApplicationContext ac, ITestBean shouldBeWeaved) { + TestBeanAdvisor tba = (TestBeanAdvisor) ac.getBean("advisor"); + + MultiplyReturnValue mrv = (MultiplyReturnValue) ac.getBean("aspect"); + assertEquals(3, mrv.getMultiple()); + + tba.count = 0; + mrv.invocations = 0; + + assertTrue("Autoproxying must apply from @AspectJ aspect", AopUtils.isAopProxy(shouldBeWeaved)); + assertEquals("Adrian", shouldBeWeaved.getName()); + assertEquals(0, mrv.invocations); + assertEquals(34 * mrv.getMultiple(), shouldBeWeaved.getAge()); + assertEquals("Spring advisor must be invoked", 2, tba.count); + assertEquals("Must be able to hold state in aspect", 1, mrv.invocations); + } + + public void testPerThisAspect() { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/perthis.xml"); + + ITestBean adrian1 = (ITestBean) bf.getBean("adrian"); + assertTrue(AopUtils.isAopProxy(adrian1)); + + assertEquals(0, adrian1.getAge()); + assertEquals(1, adrian1.getAge()); + + ITestBean adrian2 = (ITestBean) bf.getBean("adrian"); + assertNotSame(adrian1, adrian2); + assertTrue(AopUtils.isAopProxy(adrian1)); + assertEquals(0, adrian2.getAge()); + assertEquals(1, adrian2.getAge()); + assertEquals(2, adrian2.getAge()); + assertEquals(3, adrian2.getAge()); + assertEquals(2, adrian1.getAge()); + } + + public void testPerTargetAspect() throws SecurityException, NoSuchMethodException { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/pertarget.xml"); + + ITestBean adrian1 = (ITestBean) bf.getBean("adrian"); + assertTrue(AopUtils.isAopProxy(adrian1)); + + // Does not trigger advice or count + int explicitlySetAge = 25; + adrian1.setAge(explicitlySetAge); + + assertEquals("Setter does not initiate advice", explicitlySetAge, adrian1.getAge()); + // Fire aspect + + AspectMetadata am = new AspectMetadata(AbstractAspectJAdvisorFactoryTests.PerTargetAspect.class, "someBean"); + assertTrue(am.getPerClausePointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null)); + + adrian1.getSpouse(); + + assertEquals("Advice has now been instantiated", 0, adrian1.getAge()); + adrian1.setAge(11); + assertEquals("Any int setter increments", 2, adrian1.getAge()); + adrian1.setName("Adrian"); + //assertEquals("Any other setter does not increment", 2, adrian1.getAge()); + + ITestBean adrian2 = (ITestBean) bf.getBean("adrian"); + assertNotSame(adrian1, adrian2); + assertTrue(AopUtils.isAopProxy(adrian1)); + assertEquals(34, adrian2.getAge()); + adrian2.getSpouse(); + assertEquals("Aspect now fired", 0, adrian2.getAge()); + assertEquals(1, adrian2.getAge()); + assertEquals(2, adrian2.getAge()); + assertEquals(3, adrian1.getAge()); + } + + public void testTwoAdviceAspectSingleton() { + doTestTwoAdviceAspectWith("twoAdviceAspect.xml"); + } + + public void testTwoAdviceAspectPrototype() { + doTestTwoAdviceAspectWith("twoAdviceAspectPrototype.xml"); + } + + private void doTestTwoAdviceAspectWith(String location) { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/" + location); + + boolean aspectSingleton = bf.isSingleton("aspect"); + ITestBean adrian1 = (ITestBean) bf.getBean("adrian"); + testPrototype(adrian1, 0); + ITestBean adrian2 = (ITestBean) bf.getBean("adrian"); + assertNotSame(adrian1, adrian2); + testPrototype(adrian2, aspectSingleton ? 2 : 0); + } + + public void testAdviceUsingJoinPoint() { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/usesJoinPointAspect.xml"); + + ITestBean adrian1 = (ITestBean) bf.getBean("adrian"); + adrian1.getAge(); + AdviceUsingThisJoinPoint aspectInstance = (AdviceUsingThisJoinPoint) bf.getBean("aspect"); + //(AdviceUsingThisJoinPoint) Aspects.aspectOf(AdviceUsingThisJoinPoint.class); + //assertEquals("method-execution(int TestBean.getAge())",aspectInstance.getLastMethodEntered()); + assertTrue(aspectInstance.getLastMethodEntered().indexOf("TestBean.getAge())") != 0); + } + + public void testIncludeMechanism() { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/usesInclude.xml"); + + ITestBean adrian = (ITestBean) bf.getBean("adrian"); + assertTrue(AopUtils.isAopProxy(adrian)); + assertEquals(68, adrian.getAge()); + } + + private void testPrototype(ITestBean adrian1, int start) { + assertTrue(AopUtils.isAopProxy(adrian1)); + //TwoAdviceAspect twoAdviceAspect = (TwoAdviceAspect) bf.getBean(TwoAdviceAspect.class.getName()); + adrian1.setName(""); + assertEquals(start++, adrian1.getAge()); + int newAge = 32; + adrian1.setAge(newAge); + assertEquals(start++, adrian1.getAge()); + adrian1.setAge(0); + assertEquals(start++, adrian1.getAge()); + } + + public void testForceProxyTargetClass() { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/aspectsWithCGLIB.xml"); + + ProxyConfig pc = (ProxyConfig) bf.getBean(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME); + assertTrue("should be proxying classes", pc.isProxyTargetClass()); + } + + public void testWithAbstractFactoryBeanAreApplied() { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/aspectsWithAbstractBean.xml"); + + ITestBean adrian = (ITestBean) bf.getBean("adrian"); + assertTrue(AopUtils.isAopProxy(adrian)); + assertEquals(68, adrian.getAge()); + } + + public void testRetryAspect() throws Exception { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( + "/org/springframework/aop/aspectj/autoproxy/retryAspect.xml"); + UnreliableBean bean = (UnreliableBean) bf.getBean("unreliableBean"); + RetryAspect aspect = (RetryAspect) bf.getBean("retryAspect"); + int attempts = bean.unreliable(); + assertEquals(2, attempts); + assertEquals(2, aspect.getBeginCalls()); + assertEquals(1, aspect.getRollbackCalls()); + assertEquals(1, aspect.getCommitCalls()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJNamespaceHandlerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJNamespaceHandlerTests.java new file mode 100644 index 00000000000..43777b52ad5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJNamespaceHandlerTests.java @@ -0,0 +1,97 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.autoproxy; + +import junit.framework.TestCase; + +import org.springframework.aop.config.AopConfigUtils; +import org.springframework.aop.config.AopNamespaceUtils; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.parsing.CollectingReaderEventListener; +import org.springframework.beans.factory.parsing.PassThroughSourceExtractor; +import org.springframework.beans.factory.parsing.SourceExtractor; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.beans.factory.xml.XmlReaderContext; + +/** + * @author Rob Harrop + */ +public class AspectJNamespaceHandlerTests extends TestCase { + + private ParserContext parserContext; + + private CollectingReaderEventListener readerEventListener = new CollectingReaderEventListener(); + + private BeanDefinitionRegistry registry = new DefaultListableBeanFactory(); + + + protected void setUp() throws Exception { + SourceExtractor sourceExtractor = new PassThroughSourceExtractor(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.registry); + XmlReaderContext readerContext = + new XmlReaderContext(null, null, this.readerEventListener, sourceExtractor, reader, null); + this.parserContext = new ParserContext(readerContext, null); + } + + public void testRegisterAutoProxyCreator() throws Exception { + AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(this.parserContext, null); + assertEquals("Incorrect number of definitions registered", 1, registry.getBeanDefinitionCount()); + + AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(this.parserContext, null); + assertEquals("Incorrect number of definitions registered", 1, registry.getBeanDefinitionCount()); + } + + public void testRegisterAspectJAutoProxyCreator() throws Exception { + AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(this.parserContext, null); + assertEquals("Incorrect number of definitions registered", 1, registry.getBeanDefinitionCount()); + + AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(this.parserContext, null); + assertEquals("Incorrect number of definitions registered", 1, registry.getBeanDefinitionCount()); + + BeanDefinition definition = registry.getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME); + assertEquals("Incorrect APC class", + AspectJAwareAdvisorAutoProxyCreator.class.getName(), definition.getBeanClassName()); + } + + public void testRegisterAspectJAutoProxyCreatorWithExistingAutoProxyCreator() throws Exception { + AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(this.parserContext, null); + assertEquals(1, registry.getBeanDefinitionCount()); + + AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(this.parserContext, null); + assertEquals("Incorrect definition count", 1, registry.getBeanDefinitionCount()); + + BeanDefinition definition = registry.getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME); + assertEquals("APC class not switched", + AspectJAwareAdvisorAutoProxyCreator.class.getName(), definition.getBeanClassName()); + } + + public void testRegisterAutoProxyCreatorWhenAspectJAutoProxyCreatorAlreadyExists() throws Exception { + AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(this.parserContext, null); + assertEquals(1, registry.getBeanDefinitionCount()); + + AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(this.parserContext, null); + assertEquals("Incorrect definition count", 1, registry.getBeanDefinitionCount()); + + BeanDefinition definition = registry.getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME); + assertEquals("Incorrect APC class", + AspectJAwareAdvisorAutoProxyCreator.class.getName(), definition.getBeanClassName()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AtAspectJAfterThrowingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AtAspectJAfterThrowingTests.java new file mode 100644 index 00000000000..1952ea3d4a8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AtAspectJAfterThrowingTests.java @@ -0,0 +1,49 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.autoproxy; + +import junit.framework.TestCase; +import org.springframework.beans.ITestBean; +import org.springframework.aop.support.AopUtils; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import java.io.IOException; + +/** + * @author Rob Harrop + * @since 2.0 + */ +public class AtAspectJAfterThrowingTests extends TestCase { + + public void testAccessThrowable() throws Exception { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("afterThrowingAdviceTests.xml", getClass()); + + ITestBean bean = (ITestBean) context.getBean("testBean"); + ExceptionHandlingAspect aspect = (ExceptionHandlingAspect) context.getBean("aspect"); + + assertTrue(AopUtils.isAopProxy(bean)); + try { + bean.unreliableFileOperation(); + } + catch (IOException e) { + // + } + + assertEquals(1, aspect.handled); + assertNotNull(aspect.lastException); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AtAspectJAnnotationBindingTestAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AtAspectJAnnotationBindingTestAspect.java new file mode 100644 index 00000000000..4cbafcc52ad --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AtAspectJAnnotationBindingTestAspect.java @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * @author Adrian Colyer + * @author Juergen Hoeller + */ +@Aspect +public class AtAspectJAnnotationBindingTestAspect { + + @Around("execution(* *(..)) && @annotation(testAnn)") + public Object doWithAnnotation(ProceedingJoinPoint pjp, TestAnnotation testAnn) + throws Throwable { + String annValue = testAnn.value(); + Object result = pjp.proceed(); + return (result instanceof String ? annValue + " " + result : result); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AtAspectJAnnotationBindingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AtAspectJAnnotationBindingTests.java new file mode 100644 index 00000000000..aa5a08e1b78 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AtAspectJAnnotationBindingTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Adrian Colyer + * @author Juergen Hoeller + */ +public class AtAspectJAnnotationBindingTests extends AbstractDependencyInjectionSpringContextTests { + + private AnnotatedTestBean testBean; + + + public void setTestBean(AnnotatedTestBean testBean) { + this.testBean = testBean; + } + + @Override + protected String getConfigPath() { + return "ataspectj-around-advice-tests.xml"; + } + + + public void testAnnotationBindingInAroundAdvice() { + assertEquals("this value doThis", testBean.doThis()); + assertEquals("that value doThat", testBean.doThat()); + assertEquals(2, testBean.doArray().length); + } + + public void testNoMatchingWithoutAnnotationPresent() { + assertEquals("doTheOther", testBean.doTheOther()); + } + + public void testPointcutEvaulatedAgainstArray() { + applicationContext.getBean("arrayFactoryBean"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/DummyAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/DummyAspect.java new file mode 100644 index 00000000000..eb771d91cea --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/DummyAspect.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * @author Juergen Hoeller + */ +@Aspect +public class DummyAspect { + + @Around("execution(* setAge(int))") + public Object test(ProceedingJoinPoint pjp) throws Throwable { + return pjp.proceed(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/DummyAspectWithParameter.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/DummyAspectWithParameter.java new file mode 100644 index 00000000000..cb081575394 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/DummyAspectWithParameter.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * @author Juergen Hoeller + */ +@Aspect +public class DummyAspectWithParameter { + + @Around("execution(* setAge(int)) && args(age)") + public Object test(ProceedingJoinPoint pjp, int age) throws Throwable { + return pjp.proceed(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/DummyFactoryBean.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/DummyFactoryBean.java new file mode 100644 index 00000000000..41b452d770f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/DummyFactoryBean.java @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.autoproxy; + +import org.springframework.beans.factory.FactoryBean; + +/** + * @author Rob Harrop + */ +public class DummyFactoryBean implements FactoryBean { + + public Object getObject() throws Exception { + throw new UnsupportedOperationException(); + } + + public Class getObjectType() { + throw new UnsupportedOperationException(); + } + + public boolean isSingleton() { + throw new UnsupportedOperationException(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/ExceptionHandlingAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/ExceptionHandlingAspect.java new file mode 100644 index 00000000000..bcc52144403 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/ExceptionHandlingAspect.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.autoproxy; + +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; + +import java.io.IOException; + +/** + * @author Rob Harrop + * @since 2.0 + */ +@Aspect +public class ExceptionHandlingAspect { + + public int handled; + + public IOException lastException; + + @AfterThrowing(pointcut = "within(org.springframework.beans.ITestBean+)", throwing = "ex") + public void handleIOException(IOException ex) { + handled++; + lastException = ex; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/IncreaseReturnValue.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/IncreaseReturnValue.java new file mode 100644 index 00000000000..79f44dd42ff --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/IncreaseReturnValue.java @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.autoproxy; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +import org.springframework.core.annotation.Order; + +/** + * @author Juergen Hoeller + */ +@Aspect +@Order(10) +public class IncreaseReturnValue { + + @Around("execution(int *.getAge())") + public Object doubleReturnValue(ProceedingJoinPoint pjp) throws Throwable { + int result = (Integer) pjp.proceed(); + return result + 3; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/LazyTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/LazyTestBean.java new file mode 100644 index 00000000000..cc4c891f439 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/LazyTestBean.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.autoproxy; + +import org.springframework.beans.TestBean; + +/** + * @author Rod Johnson + * @since 2.0 + */ +public class LazyTestBean extends TestBean { + + public static int instantiations; + + /** + * + */ + public LazyTestBean() { + ++instantiations; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/MultiplyReturnValue.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/MultiplyReturnValue.java new file mode 100644 index 00000000000..9d940e7ac66 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/MultiplyReturnValue.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.autoproxy; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * @author Rod Johnson + */ +@Aspect +public class MultiplyReturnValue { + + private int multiple = 2; + + public int invocations; + + public void setMultiple(int multiple) { + this.multiple = multiple; + } + + public int getMultiple() { + return this.multiple; + } + + @Around("execution(int *.getAge())") + public Object doubleReturnValue(ProceedingJoinPoint pjp) throws Throwable { + ++this.invocations; + int result = (Integer) pjp.proceed(); + return result * this.multiple; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/PerThisAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/PerThisAspect.java new file mode 100644 index 00000000000..8e1b15e8f9e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/PerThisAspect.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2005 the original author 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.aop.aspectj.autoproxy; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +@Aspect("perthis(execution(* getAge()))") +public class PerThisAspect { + + private int invocations = 0; + + public int getInvocations() { + return this.invocations; + } + + @Around("execution(* getAge())") + public int changeAge(ProceedingJoinPoint pjp) throws Throwable { + return invocations++; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/ResourceArrayFactoryBean.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/ResourceArrayFactoryBean.java new file mode 100644 index 00000000000..61edc6c2107 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/ResourceArrayFactoryBean.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.core.io.Resource; + +/** + * @author Juergen Hoeller + */ +public class ResourceArrayFactoryBean implements FactoryBean { + + @TestAnnotation("some value") + public Object getObject() throws Exception { + return new Resource[0]; + } + + @TestAnnotation("some value") + public Class getObjectType() { + return Resource[].class; + } + + public boolean isSingleton() { + return true; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/RetryAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/RetryAspect.java new file mode 100644 index 00000000000..67fd0b7dbb5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/RetryAspect.java @@ -0,0 +1,83 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +@Aspect +public class RetryAspect { + + private int beginCalls; + + private int commitCalls; + + private int rollbackCalls; + + + @Pointcut("execution(public * UnreliableBean.*(..))") + public void execOfPublicMethod() { + } + + /** + * Retry Advice + */ + @Around("execOfPublicMethod()") + public Object retry(ProceedingJoinPoint jp) throws Throwable { + boolean retry = true; + Object o = null; + while (retry) { + try { + retry = false; + this.beginCalls++; + try { + o = jp.proceed(); + this.commitCalls++; + } + catch (RetryableException e) { + this.rollbackCalls++; + throw e; + } + } + catch (RetryableException re) { + retry = true; + } + } + return o; + } + + + public int getBeginCalls() { + return this.beginCalls; + } + + public int getCommitCalls() { + return this.commitCalls; + } + + public int getRollbackCalls() { + return this.rollbackCalls; + } + +} + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/RetryableException.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/RetryableException.java new file mode 100644 index 00000000000..0f66d295d33 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/RetryableException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.autoproxy; + +import org.springframework.core.NestedRuntimeException; + +/** + * @author Rob Harrop + * @since 2.0 + */ +public class RetryableException extends NestedRuntimeException { + + public RetryableException(String msg) { + super(msg); + } + + public RetryableException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/TestAnnotation.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/TestAnnotation.java new file mode 100644 index 00000000000..edc2dc690f8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/TestAnnotation.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2006 the original author 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. + * + * Created on 6 Oct 2006 by Adrian Colyer + */ +package org.springframework.aop.aspectj.autoproxy; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * @author Adrian Colyer + * @since 2.0 + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface TestAnnotation { + String value() ; +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/TestBeanAdvisor.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/TestBeanAdvisor.java new file mode 100644 index 00000000000..d1668590ebc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/TestBeanAdvisor.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2005 the original author 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.aop.aspectj.autoproxy; + +import java.lang.reflect.Method; + +import org.springframework.aop.MethodBeforeAdvice; +import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; +import org.springframework.beans.ITestBean; + +public class TestBeanAdvisor extends StaticMethodMatcherPointcutAdvisor { + + public int count; + + public TestBeanAdvisor() { + setAdvice(new MethodBeforeAdvice() { + public void before(Method method, Object[] args, Object target) throws Throwable { + ++count; + } + }); + } + + public boolean matches(Method method, Class targetClass) { + return ITestBean.class.isAssignableFrom(targetClass); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/UnreliableBean.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/UnreliableBean.java new file mode 100644 index 00000000000..4d694c225f3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/UnreliableBean.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +/** + * @author Rob Harrop + */ +public class UnreliableBean { + + private int calls; + + public int unreliable() { + this.calls++; + if (this.calls % 2 != 0) { + throw new RetryableException("foo"); + } + return this.calls; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/afterThrowingAdviceTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/afterThrowingAdviceTests.xml new file mode 100644 index 00000000000..d585ce96211 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/afterThrowingAdviceTests.xml @@ -0,0 +1,13 @@ + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/annotationPointcut.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/annotationPointcut.xml new file mode 100644 index 00000000000..63505eaa375 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/annotationPointcut.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/around-advice-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/around-advice-tests.xml new file mode 100644 index 00000000000..7e1b50d1186 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/around-advice-tests.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspects.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspects.xml new file mode 100644 index 00000000000..3eedc35b006 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspects.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsPlusAdvisor.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsPlusAdvisor.xml new file mode 100644 index 00000000000..8a399d03618 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsPlusAdvisor.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsWithAbstractBean.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsWithAbstractBean.xml new file mode 100644 index 00000000000..c1c8376b305 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsWithAbstractBean.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsWithCGLIB.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsWithCGLIB.xml new file mode 100644 index 00000000000..041fdf864d2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsWithCGLIB.xml @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsWithOrdering.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsWithOrdering.xml new file mode 100644 index 00000000000..a299f40e300 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspectsWithOrdering.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/ataspectj-around-advice-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/ataspectj-around-advice-tests.xml new file mode 100644 index 00000000000..e03eb79612a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/ataspectj-around-advice-tests.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/BenchmarkTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/BenchmarkTests.java new file mode 100644 index 00000000000..69a1219d5d9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/BenchmarkTests.java @@ -0,0 +1,168 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy.benchmark; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.Advised; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.ITestBean; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.util.StopWatch; + +/** + * Tests for AspectJ auto proxying. Includes mixing with Spring AOP + * Advisors to demonstrate that existing autoproxying contract is honoured. + * + * @author Rod Johnson + */ +public class BenchmarkTests extends TestCase { + + private static final String ASPECTJ_CONTEXT = "/org/springframework/aop/aspectj/autoproxy/benchmark/aspectj.xml"; + + private static final String SPRING_AOP_CONTEXT = "/org/springframework/aop/aspectj/autoproxy/benchmark/springAop.xml"; + + /** + * Change the return number to a higher number to make this test useful. + */ + protected int getCount() { + return 10; + } + + public void testRepeatedAroundAdviceInvocationsWithAspectJ() { + testRepeatedAroundAdviceInvocations(ASPECTJ_CONTEXT, getCount(), "AspectJ"); + } + + public void testRepeatedAroundAdviceInvocationsWithSpringAop() { + testRepeatedAroundAdviceInvocations(SPRING_AOP_CONTEXT, getCount(), "Spring AOP"); + } + + public void testRepeatedBeforeAdviceInvocationsWithAspectJ() { + testBeforeAdviceWithoutJoinPoint(ASPECTJ_CONTEXT, getCount(), "AspectJ"); + } + + public void testRepeatedBeforeAdviceInvocationsWithSpringAop() { + testBeforeAdviceWithoutJoinPoint(SPRING_AOP_CONTEXT, getCount(), "Spring AOP"); + } + + public void testRepeatedAfterReturningAdviceInvocationsWithAspectJ() { + testAfterReturningAdviceWithoutJoinPoint(ASPECTJ_CONTEXT, getCount(), "AspectJ"); + } + + public void testRepeatedAfterReturningAdviceInvocationsWithSpringAop() { + testAfterReturningAdviceWithoutJoinPoint(SPRING_AOP_CONTEXT, getCount(), "Spring AOP"); + } + + public void testRepeatedMixWithAspectJ() { + testMix(ASPECTJ_CONTEXT, getCount(), "AspectJ"); + } + + public void testRepeatedMixWithSpringAop() { + testMix(SPRING_AOP_CONTEXT, getCount(), "Spring AOP"); + } + + private long testRepeatedAroundAdviceInvocations(String file, int howmany, String technology) { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext(file); + + StopWatch sw = new StopWatch(); + sw.start(howmany + " repeated around advice invocations with " + technology); + ITestBean adrian = (ITestBean) bf.getBean("adrian"); + + assertTrue(AopUtils.isAopProxy(adrian)); + assertEquals(68, adrian.getAge()); + + for (int i = 0; i < howmany; i++) { + adrian.getAge(); + } + + sw.stop(); + System.out.println(sw.prettyPrint()); + return sw.getLastTaskTimeMillis(); + } + + private long testBeforeAdviceWithoutJoinPoint(String file, int howmany, String technology) { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext(file); + + StopWatch sw = new StopWatch(); + sw.start(howmany + " repeated before advice invocations with " + technology); + ITestBean adrian = (ITestBean) bf.getBean("adrian"); + + assertTrue(AopUtils.isAopProxy(adrian)); + Advised a = (Advised) adrian; + assertTrue(a.getAdvisors().length >= 3); + assertEquals("adrian", adrian.getName()); + + for (int i = 0; i < howmany; i++) { + adrian.getName(); + } + + sw.stop(); + System.out.println(sw.prettyPrint()); + return sw.getLastTaskTimeMillis(); + } + + private long testAfterReturningAdviceWithoutJoinPoint(String file, int howmany, String technology) { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext(file); + + StopWatch sw = new StopWatch(); + sw.start(howmany + " repeated after returning advice invocations with " + technology); + ITestBean adrian = (ITestBean) bf.getBean("adrian"); + + assertTrue(AopUtils.isAopProxy(adrian)); + Advised a = (Advised) adrian; + assertTrue(a.getAdvisors().length >= 3); + // Hits joinpoint + adrian.setAge(25); + + for (int i = 0; i < howmany; i++) { + adrian.setAge(i); + } + + sw.stop(); + System.out.println(sw.prettyPrint()); + return sw.getLastTaskTimeMillis(); + } + + private long testMix(String file, int howmany, String technology) { + ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext(file); + + StopWatch sw = new StopWatch(); + sw.start(howmany + " repeated mixed invocations with " + technology); + ITestBean adrian = (ITestBean) bf.getBean("adrian"); + + assertTrue(AopUtils.isAopProxy(adrian)); + Advised a = (Advised) adrian; + assertTrue(a.getAdvisors().length >= 3); + + for (int i = 0; i < howmany; i++) { + // Hit all 3 joinpoints + adrian.getAge(); + adrian.getName(); + adrian.setAge(i); + + // Invoke three non-advised methods + adrian.getDoctor(); + adrian.getLawyer(); + adrian.getSpouse(); + } + + sw.stop(); + System.out.println(sw.prettyPrint()); + return sw.getLastTaskTimeMillis(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/MultiplyReturnValueInterceptor.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/MultiplyReturnValueInterceptor.java new file mode 100644 index 00000000000..ce806da1c28 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/MultiplyReturnValueInterceptor.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2005 the original author 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.aop.aspectj.autoproxy.benchmark; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +public class MultiplyReturnValueInterceptor implements MethodInterceptor { + + private int multiple = 2; + + public int invocations; + + public void setMultiple(int multiple) { + this.multiple = multiple; + } + + public int getMultiple() { + return this.multiple; + } + + public Object invoke(MethodInvocation mi) throws Throwable { + ++invocations; + int result = (Integer) mi.proceed(); + return result * this.multiple; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/TraceAfterReturningAdvice.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/TraceAfterReturningAdvice.java new file mode 100644 index 00000000000..454aba80c46 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/TraceAfterReturningAdvice.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.autoproxy.benchmark; + +import java.lang.reflect.Method; + +import org.springframework.aop.Advisor; +import org.springframework.aop.AfterReturningAdvice; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.aop.support.StaticMethodMatcherPointcut; + +/** + * + * + * @author Rod Johnson + * + */ +public class TraceAfterReturningAdvice implements AfterReturningAdvice { + + public int afterTakesInt; + + public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { + ++afterTakesInt; + } + + public static Advisor advisor() { + return new DefaultPointcutAdvisor( + new StaticMethodMatcherPointcut() { + public boolean matches(Method method, Class targetClass) { + return method.getParameterTypes().length == 1 && + method.getParameterTypes()[0].equals(Integer.class); + } + }, + new TraceAfterReturningAdvice()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/TraceAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/TraceAspect.java new file mode 100644 index 00000000000..4a7fce1abb0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/TraceAspect.java @@ -0,0 +1,40 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.autoproxy.benchmark; + +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; + +@Aspect +public class TraceAspect { + + public int beforeStringReturn; + + public int afterTakesInt; + + @Before("execution(String *.*(..))") + public void traceWithoutJoinPoint() { + ++beforeStringReturn; + } + + @AfterReturning("execution(void *.*(int))") + public void traceWithoutJoinPoint2() { + ++afterTakesInt; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/TraceBeforeAdvice.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/TraceBeforeAdvice.java new file mode 100644 index 00000000000..e331bdfcf74 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/TraceBeforeAdvice.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2006 the original author 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.aop.aspectj.autoproxy.benchmark; + +import java.lang.reflect.Method; + +import org.springframework.aop.Advisor; +import org.springframework.aop.MethodBeforeAdvice; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.aop.support.StaticMethodMatcherPointcut; + +public class TraceBeforeAdvice implements MethodBeforeAdvice { + + public int beforeStringReturn; + + public void before(Method method, Object[] args, Object target) throws Throwable { + ++beforeStringReturn; + } + + public static Advisor advisor() { + return new DefaultPointcutAdvisor( + new StaticMethodMatcherPointcut() { + public boolean matches(Method method, Class targetClass) { + return method.getReturnType().equals(String.class); + } + }, + new TraceBeforeAdvice()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/aspectj.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/aspectj.xml new file mode 100644 index 00000000000..8b0975e8a93 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/aspectj.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/springAop.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/springAop.xml new file mode 100644 index 00000000000..d6c4cccceec --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/benchmark/springAop.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/lazy.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/lazy.xml new file mode 100644 index 00000000000..c8e78fc5cac --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/lazy.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/pertarget.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/pertarget.xml new file mode 100644 index 00000000000..ed540c1a5bb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/pertarget.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/perthis.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/perthis.xml new file mode 100644 index 00000000000..d2edd37111c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/perthis.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/retryAspect.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/retryAspect.xml new file mode 100644 index 00000000000..5c39c0186bf --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/retryAspect.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/SPR3064Tests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/SPR3064Tests.java new file mode 100644 index 00000000000..7044b80b8cd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/SPR3064Tests.java @@ -0,0 +1,47 @@ +/** + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.aop.aspectj.autoproxy.spr3064; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author acolyer + * + */ +public class SPR3064Tests extends AbstractDependencyInjectionSpringContextTests { + + private Service service; + + @Override + protected String[] getConfigLocations() { + return new String[] {"org/springframework/aop/aspectj/autoproxy/spr3064/annotationbinding-spr3064.xml"}; + } + + public void setService(Service service) { + this.service = service; + } + + public void testServiceIsAdvised() { + try { + this.service.serveMe(); + fail("service operation has not been advised by transaction interceptor"); + } + catch(RuntimeException ex) { + assertEquals("advice invoked",ex.getMessage()); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/Service.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/Service.java new file mode 100644 index 00000000000..deff9f8496a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/Service.java @@ -0,0 +1,26 @@ +/** + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.aop.aspectj.autoproxy.spr3064; + +/** + * @author acolyer + * + */ +public interface Service { + + void serveMe(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/ServiceImpl.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/ServiceImpl.java new file mode 100644 index 00000000000..0904f512da2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/ServiceImpl.java @@ -0,0 +1,32 @@ +/** + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.aop.aspectj.autoproxy.spr3064; + +/** + * @author acolyer + * + */ +public class ServiceImpl implements Service { + + /* (non-Javadoc) + * @see org.springframework.aop.aspectj.autoproxy.spr3064.Service#serveMe() + */ + @Transaction + public void serveMe() { + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/Transaction.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/Transaction.java new file mode 100644 index 00000000000..5e8c381bd82 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/Transaction.java @@ -0,0 +1,28 @@ +/** + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.aop.aspectj.autoproxy.spr3064; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * @author acolyer + * + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface Transaction { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/TransactionInterceptor.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/TransactionInterceptor.java new file mode 100644 index 00000000000..568c11d7c01 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/TransactionInterceptor.java @@ -0,0 +1,35 @@ +/** + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.aop.aspectj.autoproxy.spr3064; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * @author acolyer + * + */ +@Aspect +public class TransactionInterceptor { + + @Around(value="execution(* *..Service.*(..)) && @annotation(transaction)") + public Object around(ProceedingJoinPoint pjp, Transaction transaction) throws Throwable { + throw new RuntimeException("advice invoked"); + //return pjp.proceed(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/annotationbinding-spr3064.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/annotationbinding-spr3064.xml new file mode 100644 index 00000000000..567b2f1ae67 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/annotationbinding-spr3064.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/twoAdviceAspect.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/twoAdviceAspect.xml new file mode 100644 index 00000000000..4aff5af9390 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/twoAdviceAspect.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/twoAdviceAspectPrototype.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/twoAdviceAspectPrototype.xml new file mode 100644 index 00000000000..12dfcd3419a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/twoAdviceAspectPrototype.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/usesInclude.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/usesInclude.xml new file mode 100644 index 00000000000..c6da3d6ea83 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/usesInclude.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/usesJoinPointAspect.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/usesJoinPointAspect.xml new file mode 100644 index 00000000000..44bc1872f6a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/usesJoinPointAspect.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/bean-name-pointcut-atAspect-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/bean-name-pointcut-atAspect-tests.xml new file mode 100644 index 00000000000..c08dd034530 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/bean-name-pointcut-atAspect-tests.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/AfterReturningGenericTypeMatchingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/AfterReturningGenericTypeMatchingTests.java new file mode 100644 index 00000000000..ce25d83b47b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/AfterReturningGenericTypeMatchingTests.java @@ -0,0 +1,169 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.generic; + +import java.util.ArrayList; +import java.util.Collection; + +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; + +import org.springframework.beans.Employee; +import org.springframework.beans.TestBean; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * Tests ensuring that after-returning advice for generic parameters bound to + * the advice and the return type follow AspectJ semantics. + * + *

See SPR-3628 for more details. + * + * @author Ramnivas Laddad + */ +public class AfterReturningGenericTypeMatchingTests extends AbstractDependencyInjectionSpringContextTests { + + protected GenericReturnTypeVariationClass testBean; + + protected CounterAspect counterAspect; + + + public AfterReturningGenericTypeMatchingTests() { + setPopulateProtectedVariables(true); + } + + @Override + protected String getConfigPath() { + return "afterReturningGenericTypeMatchingTests-context.xml"; + } + + @Override + protected void onSetUp() throws Exception { + counterAspect.reset(); + super.onSetUp(); + } + + public void testReturnTypeExactMatching() { + testBean.getStrings(); + assertEquals(1, counterAspect.getStringsInvocationsCount); + assertEquals(0, counterAspect.getIntegersInvocationsCount); + + counterAspect.reset(); + + testBean.getIntegers(); + assertEquals(0, counterAspect.getStringsInvocationsCount); + assertEquals(1, counterAspect.getIntegersInvocationsCount); + } + + public void testReturnTypeRawMatching() { + testBean.getStrings(); + assertEquals(1, counterAspect.getRawsInvocationsCount); + + counterAspect.reset(); + + testBean.getIntegers(); + assertEquals(1, counterAspect.getRawsInvocationsCount); + } + + public void testReturnTypeUpperBoundMatching() { + testBean.getIntegers(); + assertEquals(1, counterAspect.getNumbersInvocationsCount); + } + + public void testReturnTypeLowerBoundMatching() { + testBean.getTestBeans(); + assertEquals(1, counterAspect.getTestBeanInvocationsCount); + + counterAspect.reset(); + + testBean.getEmployees(); + assertEquals(0, counterAspect.getTestBeanInvocationsCount); + } + + + public static class GenericReturnTypeVariationClass { + + public Collection getStrings() { + return new ArrayList(); + } + + public Collection getIntegers() { + return new ArrayList(); + } + + public Collection getTestBeans() { + return new ArrayList(); + } + + public Collection getEmployees() { + return new ArrayList(); + } + } + + + @Aspect + public static class CounterAspect { + + private int getRawsInvocationsCount; + + private int getStringsInvocationsCount; + + private int getIntegersInvocationsCount; + + private int getNumbersInvocationsCount; + + private int getTestBeanInvocationsCount; + + @Pointcut("execution(* org.springframework.aop.aspectj.generic.AfterReturningGenericTypeMatchingTests.GenericReturnTypeVariationClass.*(..))") + public void anyTestMethod() { + } + + @AfterReturning(pointcut = "anyTestMethod()", returning = "ret") + public void incrementGetRawsInvocationsCount(Collection ret) { + getRawsInvocationsCount++; + } + + @AfterReturning(pointcut = "anyTestMethod()", returning = "ret") + public void incrementGetStringsInvocationsCount(Collection ret) { + getStringsInvocationsCount++; + } + + @AfterReturning(pointcut = "anyTestMethod()", returning = "ret") + public void incrementGetIntegersInvocationsCount(Collection ret) { + getIntegersInvocationsCount++; + } + + @AfterReturning(pointcut = "anyTestMethod()", returning = "ret") + public void incrementGetNumbersInvocationsCount(Collection ret) { + getNumbersInvocationsCount++; + } + + @AfterReturning(pointcut = "anyTestMethod()", returning = "ret") + public void incrementTestBeanInvocationsCount(Collection ret) { + getTestBeanInvocationsCount++; + } + + public void reset() { + getRawsInvocationsCount = 0; + getStringsInvocationsCount = 0; + getIntegersInvocationsCount = 0; + getNumbersInvocationsCount = 0; + getTestBeanInvocationsCount = 0; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/GenericBridgeMethodMatchingClassProxyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/GenericBridgeMethodMatchingClassProxyTests.java new file mode 100644 index 00000000000..75442968d91 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/GenericBridgeMethodMatchingClassProxyTests.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.generic; + +/** + * Tests for AspectJ pointcut expression matching when working with bridge methods. + * + *

This class focuses on class proxying. + * + *

See GenericBridgeMethodMatchingTests for more details. + * + * @author Ramnivas Laddad + */ +public class GenericBridgeMethodMatchingClassProxyTests extends GenericBridgeMethodMatchingTests { + + @Override + protected String getConfigPath() { + return "genericBridgeMethodMatchingTests-classProxy-context.xml"; + } + + public void testGenericDerivedInterfaceMethodThroughClass() { + ((DerivedStringParameterizedClass) testBean).genericDerivedInterfaceMethod(""); + assertEquals(1, counterAspect.count); + } + + public void testGenericBaseInterfaceMethodThroughClass() { + ((DerivedStringParameterizedClass) testBean).genericBaseInterfaceMethod(""); + assertEquals(1, counterAspect.count); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/GenericBridgeMethodMatchingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/GenericBridgeMethodMatchingTests.java new file mode 100644 index 00000000000..ff5423f2b3d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/GenericBridgeMethodMatchingTests.java @@ -0,0 +1,103 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.generic; + +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * Tests for AspectJ pointcut expression matching when working with bridge methods. + * + *

Depending on the caller's static type either the bridge method or the user-implemented method + * gets called as the way into the proxy. Therefore, we need tests for calling a bean with + * static type set to type with generic method and to type with specific non-generic implementation. + * + *

This class focuses on JDK proxy, while a subclass, GenericBridgeMethodMatchingClassProxyTests, + * focuses on class proxying. + * + * See SPR-3556 for more details. + * + * @author Ramnivas Laddad + */ +public class GenericBridgeMethodMatchingTests extends AbstractDependencyInjectionSpringContextTests { + + protected DerivedInterface testBean; + + protected CounterAspect counterAspect; + + + public GenericBridgeMethodMatchingTests() { + setPopulateProtectedVariables(true); + } + + @Override + protected String getConfigPath() { + return "genericBridgeMethodMatchingTests-context.xml"; + } + + @Override + protected void onSetUp() throws Exception { + counterAspect.count = 0; + super.onSetUp(); + } + + public void testGenericDerivedInterfaceMethodThroughInterface() { + testBean.genericDerivedInterfaceMethod(""); + assertEquals(1, counterAspect.count); + } + + public void testGenericBaseInterfaceMethodThroughInterface() { + testBean.genericBaseInterfaceMethod(""); + assertEquals(1, counterAspect.count); + } + + + public interface BaseInterface { + + void genericBaseInterfaceMethod(T t); + } + + + public interface DerivedInterface extends BaseInterface { + + public void genericDerivedInterfaceMethod(T t); + } + + + public static class DerivedStringParameterizedClass implements DerivedInterface { + + public void genericDerivedInterfaceMethod(String t) { + } + + public void genericBaseInterfaceMethod(String t) { + } + } + + @Aspect + public static class CounterAspect { + + public int count; + + @Before("execution(* *..BaseInterface+.*(..))") + public void increment() { + count++; + } + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/GenericParameterMatchingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/GenericParameterMatchingTests.java new file mode 100644 index 00000000000..6fb313bcaf1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/GenericParameterMatchingTests.java @@ -0,0 +1,129 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.generic; + +import java.util.Collection; + +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * Tests that poitncut matching is correct with generic method parameter. + * See SPR-3904 for more details. + * + * @author Ramnivas Laddad + */ +public class GenericParameterMatchingTests extends AbstractDependencyInjectionSpringContextTests { + + protected CounterAspect counterAspect; + + protected GenericInterface testBean; + + + public GenericParameterMatchingTests() { + setPopulateProtectedVariables(true); + } + + @Override + protected String getConfigPath() { + return "genericParameterMatchingTests-context.xml"; + } + + @Override + protected void onSetUp() throws Exception { + counterAspect.reset(); + super.onSetUp(); + } + + + public void testGenericInterfaceGenericArgExecution() { + testBean.save(""); + assertEquals(1, counterAspect.genericInterfaceGenericArgExecutionCount); + } + + public void testGenericInterfaceGenericCollectionArgExecution() { + testBean.saveAll(null); + // TODO: uncomment once we officially update to AspectJ 1.6.0 + //assertEquals(1, counterAspect.genericInterfaceGenericCollectionArgExecutionCount); + } + + public void testGenericInterfaceSubtypeGenericCollectionArgExecution() { + testBean.saveAll(null); + assertEquals(1, counterAspect.genericInterfaceSubtypeGenericCollectionArgExecutionCount); + } + + + static interface GenericInterface { + + public void save(T bean); + + public void saveAll(Collection beans); + } + + + static class GenericImpl implements GenericInterface { + + public void save(T bean) { + } + + public void saveAll(Collection beans) { + } + } + + + @Aspect + public static class CounterAspect { + + int genericInterfaceGenericArgExecutionCount; + int genericInterfaceGenericCollectionArgExecutionCount; + int genericInterfaceSubtypeGenericCollectionArgExecutionCount; + + public void reset() { + genericInterfaceGenericArgExecutionCount = 0; + genericInterfaceGenericCollectionArgExecutionCount = 0; + genericInterfaceSubtypeGenericCollectionArgExecutionCount = 0; + } + + @Pointcut("execution(* org.springframework.aop.aspectj.generic.GenericParameterMatchingTests.GenericInterface.save(..))") + public void genericInterfaceGenericArgExecution() {} + + @Pointcut("execution(* org.springframework.aop.aspectj.generic.GenericParameterMatchingTests.GenericInterface.saveAll(..))") + public void GenericInterfaceGenericCollectionArgExecution() {} + + @Pointcut("execution(* org.springframework.aop.aspectj.generic.GenericParameterMatchingTests.GenericInterface+.saveAll(..))") + public void genericInterfaceSubtypeGenericCollectionArgExecution() {} + + @Before("genericInterfaceGenericArgExecution()") + public void incrementGenericInterfaceGenericArgExecution() { + genericInterfaceGenericArgExecutionCount++; + } + + @Before("GenericInterfaceGenericCollectionArgExecution()") + public void incrementGenericInterfaceGenericCollectionArgExecution() { + genericInterfaceGenericCollectionArgExecutionCount++; + } + + @Before("genericInterfaceSubtypeGenericCollectionArgExecution()") + public void incrementGenericInterfaceSubtypeGenericCollectionArgExecution() { + genericInterfaceSubtypeGenericCollectionArgExecutionCount++; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/afterReturningGenericTypeMatchingTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/afterReturningGenericTypeMatchingTests-context.xml new file mode 100644 index 00000000000..4edba5d74e4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/afterReturningGenericTypeMatchingTests-context.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/genericBridgeMethodMatchingTests-classProxy-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/genericBridgeMethodMatchingTests-classProxy-context.xml new file mode 100644 index 00000000000..e43671351fc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/genericBridgeMethodMatchingTests-classProxy-context.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/genericBridgeMethodMatchingTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/genericBridgeMethodMatchingTests-context.xml new file mode 100644 index 00000000000..9b65f285833 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/genericBridgeMethodMatchingTests-context.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/genericParameterMatchingTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/genericParameterMatchingTests-context.xml new file mode 100644 index 00000000000..86431f56ce7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/generic/genericParameterMatchingTests-context.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/implicit-jp-argument-matching-atAspectJ-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/implicit-jp-argument-matching-atAspectJ-tests.xml new file mode 100644 index 00000000000..01bd862dd1b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/implicit-jp-argument-matching-atAspectJ-tests.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-aspect-property-after-aspect-test.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-aspect-property-after-aspect-test.xml new file mode 100644 index 00000000000..d55ed2d65e5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-aspect-property-after-aspect-test.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-aspect-property-before-aspect-test.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-aspect-property-before-aspect-test.xml new file mode 100644 index 00000000000..89b5be547cd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-aspect-property-before-aspect-test.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-atAspectJ-aspect-property-after-aspect-test.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-atAspectJ-aspect-property-after-aspect-test.xml new file mode 100644 index 00000000000..0ec75f57379 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-atAspectJ-aspect-property-after-aspect-test.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-atAspectJ-aspect-property-before-aspect-test.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-atAspectJ-aspect-property-before-aspect-test.xml new file mode 100644 index 00000000000..6eccaebfab4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/property-dependent-atAspectJ-aspect-property-before-aspect-test.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/this-and-target-selectionOnly-pointcuts-atAspectJ-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/this-and-target-selectionOnly-pointcuts-atAspectJ-tests.xml new file mode 100644 index 00000000000..98bf02616e2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/this-and-target-selectionOnly-pointcuts-atAspectJ-tests.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/CustomEnum.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/CustomEnum.java new file mode 100644 index 00000000000..f1d7879132c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/CustomEnum.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +/** + * @author Juergen Hoeller + */ +public enum CustomEnum { + + VALUE_1, VALUE_2; + + public String toString() { + return "CustomEnum: " + name(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/GenericBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/GenericBean.java new file mode 100644 index 00000000000..c92cf099b6d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/GenericBean.java @@ -0,0 +1,237 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.springframework.core.io.Resource; + +/** + * @author Juergen Hoeller + */ +public class GenericBean { + + private Set integerSet; + + private List resourceList; + + private List> listOfLists; + + private ArrayList listOfArrays; + + private List> listOfMaps; + + private Map plainMap; + + private Map shortMap; + + private HashMap longMap; + + private Map> collectionMap; + + private Map> mapOfMaps; + + private Map> mapOfLists; + + private CustomEnum customEnum; + + private T genericProperty; + + private List genericListProperty; + + + public GenericBean() { + } + + public GenericBean(Set integerSet) { + this.integerSet = integerSet; + } + + public GenericBean(Set integerSet, List resourceList) { + this.integerSet = integerSet; + this.resourceList = resourceList; + } + + public GenericBean(HashSet integerSet, Map shortMap) { + this.integerSet = integerSet; + this.shortMap = shortMap; + } + + public GenericBean(Map shortMap, Resource resource) { + this.shortMap = shortMap; + this.resourceList = Collections.singletonList(resource); + } + + public GenericBean(Map plainMap, Map shortMap) { + this.plainMap = plainMap; + this.shortMap = shortMap; + } + + public GenericBean(HashMap longMap) { + this.longMap = longMap; + } + + public GenericBean(boolean someFlag, Map> collectionMap) { + this.collectionMap = collectionMap; + } + + + public Set getIntegerSet() { + return integerSet; + } + + public void setIntegerSet(Set integerSet) { + this.integerSet = integerSet; + } + + public List getResourceList() { + return resourceList; + } + + public void setResourceList(List resourceList) { + this.resourceList = resourceList; + } + + public List> getListOfLists() { + return listOfLists; + } + + public ArrayList getListOfArrays() { + return listOfArrays; + } + + public void setListOfArrays(ArrayList listOfArrays) { + this.listOfArrays = listOfArrays; + } + + public void setListOfLists(List> listOfLists) { + this.listOfLists = listOfLists; + } + + public List> getListOfMaps() { + return listOfMaps; + } + + public void setListOfMaps(List> listOfMaps) { + this.listOfMaps = listOfMaps; + } + + public Map getPlainMap() { + return plainMap; + } + + public Map getShortMap() { + return shortMap; + } + + public void setShortMap(Map shortMap) { + this.shortMap = shortMap; + } + + public HashMap getLongMap() { + return longMap; + } + + public void setLongMap(HashMap longMap) { + this.longMap = longMap; + } + + public Map> getCollectionMap() { + return collectionMap; + } + + public void setCollectionMap(Map> collectionMap) { + this.collectionMap = collectionMap; + } + + public Map> getMapOfMaps() { + return mapOfMaps; + } + + public void setMapOfMaps(Map> mapOfMaps) { + this.mapOfMaps = mapOfMaps; + } + + public Map> getMapOfLists() { + return mapOfLists; + } + + public void setMapOfLists(Map> mapOfLists) { + this.mapOfLists = mapOfLists; + } + + public T getGenericProperty() { + return genericProperty; + } + + public void setGenericProperty(T genericProperty) { + this.genericProperty = genericProperty; + } + + public List getGenericListProperty() { + return genericListProperty; + } + + public void setGenericListProperty(List genericListProperty) { + this.genericListProperty = genericListProperty; + } + + public CustomEnum getCustomEnum() { + return customEnum; + } + + public void setCustomEnum(CustomEnum customEnum) { + this.customEnum = customEnum; + } + + + public static GenericBean createInstance(Set integerSet) { + return new GenericBean(integerSet); + } + + public static GenericBean createInstance(Set integerSet, List resourceList) { + return new GenericBean(integerSet, resourceList); + } + + public static GenericBean createInstance(HashSet integerSet, Map shortMap) { + return new GenericBean(integerSet, shortMap); + } + + public static GenericBean createInstance(Map shortMap, Resource resource) { + return new GenericBean(shortMap, resource); + } + + public static GenericBean createInstance(Map map, Map shortMap) { + return new GenericBean(map, shortMap); + } + + public static GenericBean createInstance(HashMap longMap) { + return new GenericBean(longMap); + } + + public static GenericBean createInstance(boolean someFlag, Map> collectionMap) { + return new GenericBean(someFlag, collectionMap); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/GenericIntegerBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/GenericIntegerBean.java new file mode 100644 index 00000000000..7abdb3710fd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/GenericIntegerBean.java @@ -0,0 +1,24 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +/** + * @author Juergen Hoeller + */ +public class GenericIntegerBean extends GenericBean { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/GenericSetOfIntegerBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/GenericSetOfIntegerBean.java new file mode 100644 index 00000000000..54e18c3a179 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/GenericSetOfIntegerBean.java @@ -0,0 +1,26 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.util.Set; + +/** + * @author Juergen Hoeller + */ +public class GenericSetOfIntegerBean extends GenericBean> { + +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/AnnotationBeanWiringInfoResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/AnnotationBeanWiringInfoResolverTests.java new file mode 100644 index 00000000000..0263f26c5cc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/AnnotationBeanWiringInfoResolverTests.java @@ -0,0 +1,80 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.annotation; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.wiring.BeanWiringInfo; + +/** + * @author Rick Evans + */ +public class AnnotationBeanWiringInfoResolverTests extends TestCase { + + public void testResolveWiringInfo() throws Exception { + try { + new AnnotationBeanWiringInfoResolver().resolveWiringInfo(null); + fail("Must have thrown an IllegalArgumentException by this point (null argument)"); + } + catch (IllegalArgumentException expected) { + } + } + + public void testResolveWiringInfoWithAnInstanceOfANonAnnotatedClass() { + AnnotationBeanWiringInfoResolver resolver = new AnnotationBeanWiringInfoResolver(); + BeanWiringInfo info = resolver.resolveWiringInfo("java.lang.String is not @Configurable"); + assertNull("Must be returning null for a non-@Configurable class instance", info); + } + + public void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClass() { + AnnotationBeanWiringInfoResolver resolver = new AnnotationBeanWiringInfoResolver(); + BeanWiringInfo info = resolver.resolveWiringInfo(new Soap()); + assertNotNull("Must *not* be returning null for a non-@Configurable class instance", info); + } + + public void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClassWithAutowiringTurnedOffExplicitly() { + AnnotationBeanWiringInfoResolver resolver = new AnnotationBeanWiringInfoResolver(); + BeanWiringInfo info = resolver.resolveWiringInfo(new WirelessSoap()); + assertNotNull("Must *not* be returning null for an @Configurable class instance even when autowiring is NO", info); + assertFalse(info.indicatesAutowiring()); + assertEquals(WirelessSoap.class.getName(), info.getBeanName()); + } + + public void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClassWithAutowiringTurnedOffExplicitlyAndCustomBeanName() { + AnnotationBeanWiringInfoResolver resolver = new AnnotationBeanWiringInfoResolver(); + BeanWiringInfo info = resolver.resolveWiringInfo(new NamedWirelessSoap()); + assertNotNull("Must *not* be returning null for an @Configurable class instance even when autowiring is NO", info); + assertFalse(info.indicatesAutowiring()); + assertEquals("DerBigStick", info.getBeanName()); + } + + + @Configurable() + private static class Soap { + } + + + @Configurable(autowire = Autowire.NO) + private static class WirelessSoap { + } + + + @Configurable(autowire = Autowire.NO, value = "DerBigStick") + private static class NamedWirelessSoap { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java new file mode 100644 index 00000000000..6698d787bf0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java @@ -0,0 +1,1272 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.List; +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.IndexedTestBean; +import org.springframework.beans.NestedTestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.beans.factory.support.RootBeanDefinition; + +/** + * @author Juergen Hoeller + * @author Mark Fisher + * @author Sam Brannen + */ +public class AutowiredAnnotationBeanPostProcessorTests extends TestCase { + + public void testIncompleteBeanDefinition() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("testBean", new GenericBeanDefinition()); + try { + bf.getBean("testBean"); + } + catch (BeanCreationException ex) { + assertTrue(ex.getRootCause() instanceof IllegalStateException); + } + } + + public void testResourceInjection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + RootBeanDefinition bd = new RootBeanDefinition(ResourceInjectionBean.class); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", bd); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + + ResourceInjectionBean bean = (ResourceInjectionBean) bf.getBean("annotatedBean"); + assertSame(tb, bean.getTestBean()); + assertSame(tb, bean.getTestBean2()); + + bean = (ResourceInjectionBean) bf.getBean("annotatedBean"); + assertSame(tb, bean.getTestBean()); + assertSame(tb, bean.getTestBean2()); + } + + public void testExtendedResourceInjection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerResolvableDependency(BeanFactory.class, bf); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + RootBeanDefinition bd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", bd); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + NestedTestBean ntb = new NestedTestBean(); + bf.registerSingleton("nestedTestBean", ntb); + + TypedExtendedResourceInjectionBean bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean"); + assertSame(tb, bean.getTestBean()); + assertSame(tb, bean.getTestBean2()); + assertSame(tb, bean.getTestBean3()); + assertSame(tb, bean.getTestBean4()); + assertSame(ntb, bean.getNestedTestBean()); + assertSame(bf, bean.getBeanFactory()); + + bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean"); + assertSame(tb, bean.getTestBean()); + assertSame(tb, bean.getTestBean2()); + assertSame(tb, bean.getTestBean3()); + assertSame(tb, bean.getTestBean4()); + assertSame(ntb, bean.getNestedTestBean()); + assertSame(bf, bean.getBeanFactory()); + } + + public void testExtendedResourceInjectionWithOverriding() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerResolvableDependency(BeanFactory.class, bf); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + RootBeanDefinition annotatedBd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class); + TestBean tb2 = new TestBean(); + annotatedBd.getPropertyValues().addPropertyValue("testBean2", tb2); + bf.registerBeanDefinition("annotatedBean", annotatedBd); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + NestedTestBean ntb = new NestedTestBean(); + bf.registerSingleton("nestedTestBean", ntb); + + TypedExtendedResourceInjectionBean bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean"); + assertSame(tb, bean.getTestBean()); + assertSame(tb2, bean.getTestBean2()); + assertSame(tb, bean.getTestBean3()); + assertSame(tb, bean.getTestBean4()); + assertSame(ntb, bean.getNestedTestBean()); + assertSame(bf, bean.getBeanFactory()); + bf.destroySingletons(); + } + + public void testExtendedResourceInjectionWithAtRequired() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerResolvableDependency(BeanFactory.class, bf); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.addBeanPostProcessor(new RequiredAnnotationBeanPostProcessor()); + RootBeanDefinition bd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", bd); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + NestedTestBean ntb = new NestedTestBean(); + bf.registerSingleton("nestedTestBean", ntb); + + TypedExtendedResourceInjectionBean bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean"); + assertSame(tb, bean.getTestBean()); + assertSame(tb, bean.getTestBean2()); + assertSame(tb, bean.getTestBean3()); + assertSame(tb, bean.getTestBean4()); + assertSame(ntb, bean.getNestedTestBean()); + assertSame(bf, bean.getBeanFactory()); + } + + public void testOptionalResourceInjection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalResourceInjectionBean.class)); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + IndexedTestBean itb = new IndexedTestBean(); + bf.registerSingleton("indexedTestBean", itb); + NestedTestBean ntb1 = new NestedTestBean(); + bf.registerSingleton("nestedTestBean1", ntb1); + NestedTestBean ntb2 = new NestedTestBean(); + bf.registerSingleton("nestedTestBean2", ntb2); + + OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean"); + assertSame(tb, bean.getTestBean()); + assertSame(tb, bean.getTestBean2()); + assertSame(tb, bean.getTestBean3()); + assertSame(tb, bean.getTestBean4()); + assertSame(itb, bean.getIndexedTestBean()); + assertEquals(2, bean.getNestedTestBeans().length); + assertSame(ntb1, bean.getNestedTestBeans()[0]); + assertSame(ntb2, bean.getNestedTestBeans()[1]); + assertEquals(2, bean.nestedTestBeansField.length); + assertSame(ntb1, bean.nestedTestBeansField[0]); + assertSame(ntb2, bean.nestedTestBeansField[1]); + bf.destroySingletons(); + } + + public void testOptionalCollectionResourceInjection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + RootBeanDefinition rbd = new RootBeanDefinition(OptionalCollectionResourceInjectionBean.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", rbd); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + IndexedTestBean itb = new IndexedTestBean(); + bf.registerSingleton("indexedTestBean", itb); + NestedTestBean ntb1 = new NestedTestBean(); + bf.registerSingleton("nestedTestBean1", ntb1); + NestedTestBean ntb2 = new NestedTestBean(); + bf.registerSingleton("nestedTestBean2", ntb2); + + // Two calls to verify that caching doesn't break re-creation. + OptionalCollectionResourceInjectionBean bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean"); + bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean"); + assertSame(tb, bean.getTestBean()); + assertSame(tb, bean.getTestBean2()); + assertSame(tb, bean.getTestBean3()); + assertSame(tb, bean.getTestBean4()); + assertSame(itb, bean.getIndexedTestBean()); + assertEquals(2, bean.getNestedTestBeans().size()); + assertSame(ntb1, bean.getNestedTestBeans().get(0)); + assertSame(ntb2, bean.getNestedTestBeans().get(1)); + assertEquals(2, bean.nestedTestBeansSetter.size()); + assertSame(ntb1, bean.nestedTestBeansSetter.get(0)); + assertSame(ntb2, bean.nestedTestBeansSetter.get(1)); + assertEquals(2, bean.nestedTestBeansField.size()); + assertSame(ntb1, bean.nestedTestBeansField.get(0)); + assertSame(ntb2, bean.nestedTestBeansField.get(1)); + bf.destroySingletons(); + } + + public void testOptionalCollectionResourceInjectionWithSingleElement() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + RootBeanDefinition rbd = new RootBeanDefinition(OptionalCollectionResourceInjectionBean.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", rbd); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + IndexedTestBean itb = new IndexedTestBean(); + bf.registerSingleton("indexedTestBean", itb); + NestedTestBean ntb1 = new NestedTestBean(); + bf.registerSingleton("nestedTestBean1", ntb1); + + // Two calls to verify that caching doesn't break re-creation. + OptionalCollectionResourceInjectionBean bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean"); + bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean"); + assertSame(tb, bean.getTestBean()); + assertSame(tb, bean.getTestBean2()); + assertSame(tb, bean.getTestBean3()); + assertSame(tb, bean.getTestBean4()); + assertSame(itb, bean.getIndexedTestBean()); + assertEquals(1, bean.getNestedTestBeans().size()); + assertSame(ntb1, bean.getNestedTestBeans().get(0)); + assertEquals(1, bean.nestedTestBeansSetter.size()); + assertSame(ntb1, bean.nestedTestBeansSetter.get(0)); + assertEquals(1, bean.nestedTestBeansField.size()); + assertSame(ntb1, bean.nestedTestBeansField.get(0)); + bf.destroySingletons(); + } + + public void testOptionalResourceInjectionWithIncompleteDependencies() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalResourceInjectionBean.class)); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + + OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean"); + assertSame(tb, bean.getTestBean()); + assertSame(tb, bean.getTestBean2()); + assertSame(tb, bean.getTestBean3()); + assertNull(bean.getTestBean4()); + assertNull(bean.getNestedTestBeans()); + bf.destroySingletons(); + } + + public void testOptionalResourceInjectionWithNoDependencies() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalResourceInjectionBean.class)); + + OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean"); + assertNull(bean.getTestBean()); + assertNull(bean.getTestBean2()); + assertNull(bean.getTestBean3()); + assertNull(bean.getTestBean4()); + assertNull(bean.getNestedTestBeans()); + bf.destroySingletons(); + } + + public void testConstructorResourceInjection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerResolvableDependency(BeanFactory.class, bf); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", bd); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + NestedTestBean ntb = new NestedTestBean(); + bf.registerSingleton("nestedTestBean", ntb); + + ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean"); + assertSame(tb, bean.getTestBean()); + assertSame(tb, bean.getTestBean2()); + assertSame(tb, bean.getTestBean3()); + assertSame(tb, bean.getTestBean4()); + assertSame(ntb, bean.getNestedTestBean()); + assertSame(bf, bean.getBeanFactory()); + + bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean"); + assertSame(tb, bean.getTestBean()); + assertSame(tb, bean.getTestBean2()); + assertSame(tb, bean.getTestBean3()); + assertSame(tb, bean.getTestBean4()); + assertSame(ntb, bean.getNestedTestBean()); + assertSame(bf, bean.getBeanFactory()); + } + + public void testConstructorResourceInjectionWithMultipleCandidates() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ConstructorsResourceInjectionBean.class)); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + NestedTestBean ntb1 = new NestedTestBean(); + bf.registerSingleton("nestedTestBean1", ntb1); + NestedTestBean ntb2 = new NestedTestBean(); + bf.registerSingleton("nestedTestBean2", ntb2); + + ConstructorsResourceInjectionBean bean = (ConstructorsResourceInjectionBean) bf.getBean("annotatedBean"); + assertNull(bean.getTestBean3()); + assertSame(tb, bean.getTestBean4()); + assertEquals(2, bean.getNestedTestBeans().length); + assertSame(ntb1, bean.getNestedTestBeans()[0]); + assertSame(ntb2, bean.getNestedTestBeans()[1]); + bf.destroySingletons(); + } + + public void testConstructorResourceInjectionWithMultipleCandidatesAsCollection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition( + ConstructorsCollectionResourceInjectionBean.class)); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + NestedTestBean ntb1 = new NestedTestBean(); + bf.registerSingleton("nestedTestBean1", ntb1); + NestedTestBean ntb2 = new NestedTestBean(); + bf.registerSingleton("nestedTestBean2", ntb2); + + ConstructorsCollectionResourceInjectionBean bean = (ConstructorsCollectionResourceInjectionBean) bf.getBean("annotatedBean"); + assertNull(bean.getTestBean3()); + assertSame(tb, bean.getTestBean4()); + assertEquals(2, bean.getNestedTestBeans().size()); + assertSame(ntb1, bean.getNestedTestBeans().get(0)); + assertSame(ntb2, bean.getNestedTestBeans().get(1)); + bf.destroySingletons(); + } + + public void testConstructorResourceInjectionWithMultipleCandidatesAndFallback() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ConstructorsResourceInjectionBean.class)); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + + ConstructorsResourceInjectionBean bean = (ConstructorsResourceInjectionBean) bf.getBean("annotatedBean"); + assertSame(tb, bean.getTestBean3()); + assertNull(bean.getTestBean4()); + bf.destroySingletons(); + } + + public void testConstructorResourceInjectionWithMultipleCandidatesAndDefaultFallback() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ConstructorsResourceInjectionBean.class)); + + ConstructorsResourceInjectionBean bean = (ConstructorsResourceInjectionBean) bf.getBean("annotatedBean"); + assertNull(bean.getTestBean3()); + assertNull(bean.getTestBean4()); + bf.destroySingletons(); + } + + public void testConstructorInjectionWithMap() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + RootBeanDefinition bd = new RootBeanDefinition(MapConstructorInjectionBean.class); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", bd); + TestBean tb1 = new TestBean(); + TestBean tb2 = new TestBean(); + bf.registerSingleton("testBean1", tb1); + bf.registerSingleton("testBean2", tb1); + + MapConstructorInjectionBean bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean"); + assertEquals(2, bean.getTestBeanMap().size()); + assertTrue(bean.getTestBeanMap().keySet().contains("testBean1")); + assertTrue(bean.getTestBeanMap().keySet().contains("testBean2")); + assertTrue(bean.getTestBeanMap().values().contains(tb1)); + assertTrue(bean.getTestBeanMap().values().contains(tb2)); + + bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean"); + assertEquals(2, bean.getTestBeanMap().size()); + assertTrue(bean.getTestBeanMap().keySet().contains("testBean1")); + assertTrue(bean.getTestBeanMap().keySet().contains("testBean2")); + assertTrue(bean.getTestBeanMap().values().contains(tb1)); + assertTrue(bean.getTestBeanMap().values().contains(tb2)); + } + + public void testFieldInjectionWithMap() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + RootBeanDefinition bd = new RootBeanDefinition(MapFieldInjectionBean.class); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", bd); + TestBean tb1 = new TestBean(); + TestBean tb2 = new TestBean(); + bf.registerSingleton("testBean1", tb1); + bf.registerSingleton("testBean2", tb1); + + MapFieldInjectionBean bean = (MapFieldInjectionBean) bf.getBean("annotatedBean"); + assertEquals(2, bean.getTestBeanMap().size()); + assertTrue(bean.getTestBeanMap().keySet().contains("testBean1")); + assertTrue(bean.getTestBeanMap().keySet().contains("testBean2")); + assertTrue(bean.getTestBeanMap().values().contains(tb1)); + assertTrue(bean.getTestBeanMap().values().contains(tb2)); + + bean = (MapFieldInjectionBean) bf.getBean("annotatedBean"); + assertEquals(2, bean.getTestBeanMap().size()); + assertTrue(bean.getTestBeanMap().keySet().contains("testBean1")); + assertTrue(bean.getTestBeanMap().keySet().contains("testBean2")); + assertTrue(bean.getTestBeanMap().values().contains(tb1)); + assertTrue(bean.getTestBeanMap().values().contains(tb2)); + } + + public void testMethodInjectionWithMap() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + RootBeanDefinition bd = new RootBeanDefinition(MapMethodInjectionBean.class); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", bd); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + + MapMethodInjectionBean bean = (MapMethodInjectionBean) bf.getBean("annotatedBean"); + assertEquals(1, bean.getTestBeanMap().size()); + assertTrue(bean.getTestBeanMap().keySet().contains("testBean")); + assertTrue(bean.getTestBeanMap().values().contains(tb)); + assertSame(tb, bean.getTestBean()); + + bean = (MapMethodInjectionBean) bf.getBean("annotatedBean"); + assertEquals(1, bean.getTestBeanMap().size()); + assertTrue(bean.getTestBeanMap().keySet().contains("testBean")); + assertTrue(bean.getTestBeanMap().values().contains(tb)); + assertSame(tb, bean.getTestBean()); + } + + public void testMethodInjectionWithMapAndMultipleMatches() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class)); + bf.registerBeanDefinition("testBean1", new RootBeanDefinition(TestBean.class)); + bf.registerBeanDefinition("testBean2", new RootBeanDefinition(TestBean.class)); + + try { + MapMethodInjectionBean bean = (MapMethodInjectionBean) bf.getBean("annotatedBean"); + fail("should have failed, more than one bean of type"); + } + catch (BeanCreationException e) { + // expected + } + bf.destroySingletons(); + } + + public void testMethodInjectionWithMapAndMultipleMatchesButOnlyOneAutowireCandidate() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class)); + bf.registerBeanDefinition("testBean1", new RootBeanDefinition(TestBean.class)); + RootBeanDefinition rbd2 = new RootBeanDefinition(TestBean.class); + rbd2.setAutowireCandidate(false); + bf.registerBeanDefinition("testBean2", rbd2); + + MapMethodInjectionBean bean = (MapMethodInjectionBean) bf.getBean("annotatedBean"); + TestBean tb = (TestBean) bf.getBean("testBean1"); + assertEquals(1, bean.getTestBeanMap().size()); + assertTrue(bean.getTestBeanMap().keySet().contains("testBean1")); + assertTrue(bean.getTestBeanMap().values().contains(tb)); + assertSame(tb, bean.getTestBean()); + bf.destroySingletons(); + } + + public void testMethodInjectionWithMapAndNoMatches() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class)); + + MapMethodInjectionBean bean = (MapMethodInjectionBean) bf.getBean("annotatedBean"); + assertNull(bean.getTestBeanMap()); + assertNull(bean.getTestBean()); + bf.destroySingletons(); + } + + public void testCustomAnnotationRequiredFieldResourceInjection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setAutowiredAnnotationType(MyAutowired.class); + bpp.setRequiredParameterName("optional"); + bpp.setRequiredParameterValue(false); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("customBean", new RootBeanDefinition( + CustomAnnotationRequiredFieldResourceInjectionBean.class)); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + + CustomAnnotationRequiredFieldResourceInjectionBean bean = (CustomAnnotationRequiredFieldResourceInjectionBean) bf.getBean("customBean"); + assertSame(tb, bean.getTestBean()); + bf.destroySingletons(); + } + + public void testCustomAnnotationRequiredFieldResourceInjectionFailsWhenNoDependencyFound() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setAutowiredAnnotationType(MyAutowired.class); + bpp.setRequiredParameterName("optional"); + bpp.setRequiredParameterValue(false); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("customBean", new RootBeanDefinition( + CustomAnnotationRequiredFieldResourceInjectionBean.class)); + + try { + bf.getBean("customBean"); + fail("expected BeanCreationException; no dependency available for required field"); + } + catch (BeanCreationException e) { + // expected + } + bf.destroySingletons(); + } + + public void testCustomAnnotationRequiredFieldResourceInjectionFailsWhenMultipleDependenciesFound() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setAutowiredAnnotationType(MyAutowired.class); + bpp.setRequiredParameterName("optional"); + bpp.setRequiredParameterValue(false); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("customBean", new RootBeanDefinition( + CustomAnnotationRequiredFieldResourceInjectionBean.class)); + TestBean tb1 = new TestBean(); + bf.registerSingleton("testBean1", tb1); + TestBean tb2 = new TestBean(); + bf.registerSingleton("testBean2", tb2); + + try { + bf.getBean("customBean"); + fail("expected BeanCreationException; multiple beans of dependency type available"); + } + catch (BeanCreationException e) { + // expected + } + bf.destroySingletons(); + } + + public void testCustomAnnotationRequiredMethodResourceInjection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setAutowiredAnnotationType(MyAutowired.class); + bpp.setRequiredParameterName("optional"); + bpp.setRequiredParameterValue(false); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("customBean", new RootBeanDefinition( + CustomAnnotationRequiredMethodResourceInjectionBean.class)); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + + CustomAnnotationRequiredMethodResourceInjectionBean bean = (CustomAnnotationRequiredMethodResourceInjectionBean) bf.getBean("customBean"); + assertSame(tb, bean.getTestBean()); + bf.destroySingletons(); + } + + public void testCustomAnnotationRequiredMethodResourceInjectionFailsWhenNoDependencyFound() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setAutowiredAnnotationType(MyAutowired.class); + bpp.setRequiredParameterName("optional"); + bpp.setRequiredParameterValue(false); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("customBean", new RootBeanDefinition( + CustomAnnotationRequiredMethodResourceInjectionBean.class)); + + try { + bf.getBean("customBean"); + fail("expected BeanCreationException; no dependency available for required method"); + } + catch (BeanCreationException e) { + // expected + } + bf.destroySingletons(); + } + + public void testCustomAnnotationRequiredMethodResourceInjectionFailsWhenMultipleDependenciesFound() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setAutowiredAnnotationType(MyAutowired.class); + bpp.setRequiredParameterName("optional"); + bpp.setRequiredParameterValue(false); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("customBean", new RootBeanDefinition( + CustomAnnotationRequiredMethodResourceInjectionBean.class)); + TestBean tb1 = new TestBean(); + bf.registerSingleton("testBean1", tb1); + TestBean tb2 = new TestBean(); + bf.registerSingleton("testBean2", tb2); + + try { + bf.getBean("customBean"); + fail("expected BeanCreationException; multiple beans of dependency type available"); + } + catch (BeanCreationException e) { + // expected + } + bf.destroySingletons(); + } + + public void testCustomAnnotationOptionalFieldResourceInjection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setAutowiredAnnotationType(MyAutowired.class); + bpp.setRequiredParameterName("optional"); + bpp.setRequiredParameterValue(false); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("customBean", new RootBeanDefinition( + CustomAnnotationOptionalFieldResourceInjectionBean.class)); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + + CustomAnnotationOptionalFieldResourceInjectionBean bean = (CustomAnnotationOptionalFieldResourceInjectionBean) bf.getBean("customBean"); + assertSame(tb, bean.getTestBean3()); + assertNull(bean.getTestBean()); + assertNull(bean.getTestBean2()); + bf.destroySingletons(); + } + + public void testCustomAnnotationOptionalFieldResourceInjectionWhenNoDependencyFound() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setAutowiredAnnotationType(MyAutowired.class); + bpp.setRequiredParameterName("optional"); + bpp.setRequiredParameterValue(false); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("customBean", new RootBeanDefinition( + CustomAnnotationOptionalFieldResourceInjectionBean.class)); + + CustomAnnotationOptionalFieldResourceInjectionBean bean = (CustomAnnotationOptionalFieldResourceInjectionBean) bf.getBean("customBean"); + assertNull(bean.getTestBean3()); + assertNull(bean.getTestBean()); + assertNull(bean.getTestBean2()); + bf.destroySingletons(); + } + + public void testCustomAnnotationOptionalFieldResourceInjectionWhenMultipleDependenciesFound() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setAutowiredAnnotationType(MyAutowired.class); + bpp.setRequiredParameterName("optional"); + bpp.setRequiredParameterValue(false); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("customBean", new RootBeanDefinition( + CustomAnnotationOptionalFieldResourceInjectionBean.class)); + TestBean tb1 = new TestBean(); + bf.registerSingleton("testBean1", tb1); + TestBean tb2 = new TestBean(); + bf.registerSingleton("testBean2", tb2); + + try { + bf.getBean("customBean"); + fail("expected BeanCreationException; multiple beans of dependency type available"); + } + catch (BeanCreationException e) { + // expected + } + bf.destroySingletons(); + } + + public void testCustomAnnotationOptionalMethodResourceInjection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setAutowiredAnnotationType(MyAutowired.class); + bpp.setRequiredParameterName("optional"); + bpp.setRequiredParameterValue(false); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("customBean", new RootBeanDefinition( + CustomAnnotationOptionalMethodResourceInjectionBean.class)); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + + CustomAnnotationOptionalMethodResourceInjectionBean bean = (CustomAnnotationOptionalMethodResourceInjectionBean) bf.getBean("customBean"); + assertSame(tb, bean.getTestBean3()); + assertNull(bean.getTestBean()); + assertNull(bean.getTestBean2()); + bf.destroySingletons(); + } + + public void testCustomAnnotationOptionalMethodResourceInjectionWhenNoDependencyFound() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setAutowiredAnnotationType(MyAutowired.class); + bpp.setRequiredParameterName("optional"); + bpp.setRequiredParameterValue(false); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("customBean", new RootBeanDefinition( + CustomAnnotationOptionalMethodResourceInjectionBean.class)); + + CustomAnnotationOptionalMethodResourceInjectionBean bean = (CustomAnnotationOptionalMethodResourceInjectionBean) bf.getBean("customBean"); + assertNull(bean.getTestBean3()); + assertNull(bean.getTestBean()); + assertNull(bean.getTestBean2()); + bf.destroySingletons(); + } + + public void testCustomAnnotationOptionalMethodResourceInjectionWhenMultipleDependenciesFound() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setAutowiredAnnotationType(MyAutowired.class); + bpp.setRequiredParameterName("optional"); + bpp.setRequiredParameterValue(false); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("customBean", new RootBeanDefinition( + CustomAnnotationOptionalMethodResourceInjectionBean.class)); + TestBean tb1 = new TestBean(); + bf.registerSingleton("testBean1", tb1); + TestBean tb2 = new TestBean(); + bf.registerSingleton("testBean2", tb2); + + try { + bf.getBean("customBean"); + fail("expected BeanCreationException; multiple beans of dependency type available"); + } + catch (BeanCreationException e) { + // expected + } + bf.destroySingletons(); + } + + /** + * Verifies that a dependency on a {@link FactoryBean} can be autowired via + * {@link Autowired @Autowired}, specifically addressing the JIRA issue + * raised in SPR-4040. + */ + public void testBeanAutowiredWithFactoryBean() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("factoryBeanDependentBean", new RootBeanDefinition(FactoryBeanDependentBean.class)); + bf.registerSingleton("stringFactoryBean", new StringFactoryBean()); + + final StringFactoryBean factoryBean = (StringFactoryBean) bf.getBean("&stringFactoryBean"); + final FactoryBeanDependentBean bean = (FactoryBeanDependentBean) bf.getBean("factoryBeanDependentBean"); + + assertNotNull("The singleton StringFactoryBean should have been registered.", factoryBean); + assertNotNull("The factoryBeanDependentBean should have been registered.", bean); + assertEquals("The FactoryBeanDependentBean should have been autowired 'by type' with the StringFactoryBean.", + factoryBean, bean.getFactoryBean()); + + bf.destroySingletons(); + } + + + public static class ResourceInjectionBean { + + @Autowired(required = false) + private TestBean testBean; + + private TestBean testBean2; + + + @Autowired + public void setTestBean2(TestBean testBean2) { + if (this.testBean2 != null) { + throw new IllegalStateException("Already called"); + } + this.testBean2 = testBean2; + } + + public TestBean getTestBean() { + return this.testBean; + } + + public TestBean getTestBean2() { + return this.testBean2; + } + } + + + public static class ExtendedResourceInjectionBean extends ResourceInjectionBean { + + @Autowired + protected ITestBean testBean3; + + private T nestedTestBean; + + private ITestBean testBean4; + + private BeanFactory beanFactory; + + public ExtendedResourceInjectionBean() { + } + + @Autowired @Required + public void setTestBean2(TestBean testBean2) { + super.setTestBean2(testBean2); + } + + @Autowired + private void inject(ITestBean testBean4, T nestedTestBean) { + this.testBean4 = testBean4; + this.nestedTestBean = nestedTestBean; + } + + @Autowired + protected void initBeanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + public ITestBean getTestBean3() { + return this.testBean3; + } + + public ITestBean getTestBean4() { + return this.testBean4; + } + + public T getNestedTestBean() { + return this.nestedTestBean; + } + + public BeanFactory getBeanFactory() { + return this.beanFactory; + } + } + + + public static class TypedExtendedResourceInjectionBean extends ExtendedResourceInjectionBean { + + } + + + public static class OptionalResourceInjectionBean extends ResourceInjectionBean { + + @Autowired(required = false) + protected ITestBean testBean3; + + private IndexedTestBean indexedTestBean; + + private NestedTestBean[] nestedTestBeans; + + @Autowired(required = false) + public NestedTestBean[] nestedTestBeansField; + + private ITestBean testBean4; + + @Autowired(required = false) + public void setTestBean2(TestBean testBean2) { + super.setTestBean2(testBean2); + } + + @Autowired(required = false) + private void inject(ITestBean testBean4, NestedTestBean[] nestedTestBeans, IndexedTestBean indexedTestBean) { + this.testBean4 = testBean4; + this.indexedTestBean = indexedTestBean; + this.nestedTestBeans = nestedTestBeans; + } + + public ITestBean getTestBean3() { + return this.testBean3; + } + + public ITestBean getTestBean4() { + return this.testBean4; + } + + public IndexedTestBean getIndexedTestBean() { + return this.indexedTestBean; + } + + public NestedTestBean[] getNestedTestBeans() { + return this.nestedTestBeans; + } + } + + + public static class OptionalCollectionResourceInjectionBean extends ResourceInjectionBean { + + @Autowired(required = false) + protected ITestBean testBean3; + + private IndexedTestBean indexedTestBean; + + private List nestedTestBeans; + + public List nestedTestBeansSetter; + + @Autowired(required = false) + public List nestedTestBeansField; + + private ITestBean testBean4; + + @Autowired(required = false) + public void setTestBean2(TestBean testBean2) { + super.setTestBean2(testBean2); + } + + @Autowired(required = false) + private void inject(ITestBean testBean4, List nestedTestBeans, IndexedTestBean indexedTestBean) { + this.testBean4 = testBean4; + this.indexedTestBean = indexedTestBean; + this.nestedTestBeans = nestedTestBeans; + } + + @Autowired(required = false) + public void setNestedTestBeans(List nestedTestBeans) { + this.nestedTestBeansSetter = nestedTestBeans; + } + + public ITestBean getTestBean3() { + return this.testBean3; + } + + public ITestBean getTestBean4() { + return this.testBean4; + } + + public IndexedTestBean getIndexedTestBean() { + return this.indexedTestBean; + } + + public List getNestedTestBeans() { + return this.nestedTestBeans; + } + } + + + public static class ConstructorResourceInjectionBean extends ResourceInjectionBean { + + @Autowired + protected ITestBean testBean3; + + private ITestBean testBean4; + + private NestedTestBean nestedTestBean; + + private ConfigurableListableBeanFactory beanFactory; + + + public ConstructorResourceInjectionBean() { + throw new UnsupportedOperationException(); + } + + public ConstructorResourceInjectionBean(ITestBean testBean3) { + throw new UnsupportedOperationException(); + } + + @Autowired + public ConstructorResourceInjectionBean(ITestBean testBean4, NestedTestBean nestedTestBean, + ConfigurableListableBeanFactory beanFactory) { + this.testBean4 = testBean4; + this.nestedTestBean = nestedTestBean; + this.beanFactory = beanFactory; + } + + public ConstructorResourceInjectionBean(NestedTestBean nestedTestBean) { + throw new UnsupportedOperationException(); + } + + public ConstructorResourceInjectionBean(ITestBean testBean3, ITestBean testBean4, NestedTestBean nestedTestBean) { + throw new UnsupportedOperationException(); + } + + @Autowired + public void setTestBean2(TestBean testBean2) { + super.setTestBean2(testBean2); + } + + public ITestBean getTestBean3() { + return this.testBean3; + } + + public ITestBean getTestBean4() { + return this.testBean4; + } + + public NestedTestBean getNestedTestBean() { + return this.nestedTestBean; + } + + public ConfigurableListableBeanFactory getBeanFactory() { + return this.beanFactory; + } + } + + + public static class ConstructorsResourceInjectionBean { + + protected ITestBean testBean3; + + private ITestBean testBean4; + + private NestedTestBean[] nestedTestBeans; + + public ConstructorsResourceInjectionBean() { + } + + @Autowired(required = false) + public ConstructorsResourceInjectionBean(ITestBean testBean3) { + this.testBean3 = testBean3; + } + + @Autowired(required = false) + public ConstructorsResourceInjectionBean(ITestBean testBean4, NestedTestBean[] nestedTestBeans) { + this.testBean4 = testBean4; + this.nestedTestBeans = nestedTestBeans; + } + + public ConstructorsResourceInjectionBean(NestedTestBean nestedTestBean) { + throw new UnsupportedOperationException(); + } + + public ConstructorsResourceInjectionBean(ITestBean testBean3, ITestBean testBean4, NestedTestBean nestedTestBean) { + throw new UnsupportedOperationException(); + } + + public ITestBean getTestBean3() { + return this.testBean3; + } + + public ITestBean getTestBean4() { + return this.testBean4; + } + + public NestedTestBean[] getNestedTestBeans() { + return this.nestedTestBeans; + } + } + + + public static class ConstructorsCollectionResourceInjectionBean { + + protected ITestBean testBean3; + + private ITestBean testBean4; + + private List nestedTestBeans; + + public ConstructorsCollectionResourceInjectionBean() { + } + + @Autowired(required = false) + public ConstructorsCollectionResourceInjectionBean(ITestBean testBean3) { + this.testBean3 = testBean3; + } + + @Autowired(required = false) + public ConstructorsCollectionResourceInjectionBean(ITestBean testBean4, List nestedTestBeans) { + this.testBean4 = testBean4; + this.nestedTestBeans = nestedTestBeans; + } + + public ConstructorsCollectionResourceInjectionBean(NestedTestBean nestedTestBean) { + throw new UnsupportedOperationException(); + } + + public ConstructorsCollectionResourceInjectionBean(ITestBean testBean3, ITestBean testBean4, + NestedTestBean nestedTestBean) { + throw new UnsupportedOperationException(); + } + + public ITestBean getTestBean3() { + return this.testBean3; + } + + public ITestBean getTestBean4() { + return this.testBean4; + } + + public List getNestedTestBeans() { + return this.nestedTestBeans; + } + } + + + public static class MapConstructorInjectionBean { + + private Map testBeanMap; + + @Autowired + public MapConstructorInjectionBean(Map testBeanMap) { + this.testBeanMap = testBeanMap; + } + + public Map getTestBeanMap() { + return this.testBeanMap; + } + } + + + public static class MapFieldInjectionBean { + + @Autowired + private Map testBeanMap; + + + public Map getTestBeanMap() { + return this.testBeanMap; + } + } + + + public static class MapMethodInjectionBean { + + private TestBean testBean; + + private Map testBeanMap; + + @Autowired(required = false) + public void setTestBeanMap(TestBean testBean, Map testBeanMap) { + this.testBean = testBean; + this.testBeanMap = testBeanMap; + } + + public TestBean getTestBean() { + return this.testBean; + } + + public Map getTestBeanMap() { + return this.testBeanMap; + } + } + + + public static class CustomAnnotationRequiredFieldResourceInjectionBean { + + @MyAutowired(optional = false) + private TestBean testBean; + + public TestBean getTestBean() { + return this.testBean; + } + } + + + public static class CustomAnnotationRequiredMethodResourceInjectionBean { + + private TestBean testBean; + + @MyAutowired(optional = false) + public void setTestBean(TestBean testBean) { + this.testBean = testBean; + } + + public TestBean getTestBean() { + return this.testBean; + } + } + + + public static class CustomAnnotationOptionalFieldResourceInjectionBean extends ResourceInjectionBean { + + @MyAutowired(optional = true) + private TestBean testBean3; + + public TestBean getTestBean3() { + return this.testBean3; + } + } + + + public static class CustomAnnotationOptionalMethodResourceInjectionBean extends ResourceInjectionBean { + + private TestBean testBean3; + + + @MyAutowired(optional = true) + protected void setTestBean3(TestBean testBean3) { + this.testBean3 = testBean3; + } + + public TestBean getTestBean3() { + return this.testBean3; + } + } + + + @Target({ElementType.METHOD, ElementType.FIELD}) + @Retention(RetentionPolicy.RUNTIME) + public static @interface MyAutowired { + + boolean optional() default false; + } + + + /** + * Bean with a dependency on a {@link FactoryBean}. + */ + private static class FactoryBeanDependentBean { + + @Autowired + private FactoryBean factoryBean; + + public final FactoryBean getFactoryBean() { + return this.factoryBean; + } + } + + + public static class StringFactoryBean implements FactoryBean { + + public Object getObject() throws Exception { + return ""; + } + + public Class getObjectType() { + return String.class; + } + + public boolean isSingleton() { + return true; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/CustomAutowireConfigurerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/CustomAutowireConfigurerTests.java new file mode 100644 index 00000000000..22310cc587c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/CustomAutowireConfigurerTests.java @@ -0,0 +1,81 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.annotation; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.DependencyDescriptor; +import org.springframework.beans.factory.support.AutowireCandidateResolver; +import org.springframework.beans.factory.support.BeanDefinitionReader; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +public class CustomAutowireConfigurerTests extends TestCase { + + private static final String CONFIG_LOCATION = + "classpath:org/springframework/beans/factory/annotation/customAutowireConfigurer.xml"; + + + public void testCustomResolver() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(bf); + reader.loadBeanDefinitions(CONFIG_LOCATION); + CustomAutowireConfigurer cac = new CustomAutowireConfigurer(); + CustomResolver customResolver = new CustomResolver(); + bf.setAutowireCandidateResolver(customResolver); + cac.postProcessBeanFactory(bf); + TestBean testBean = (TestBean) bf.getBean("testBean"); + assertEquals("#1!", testBean.getName()); + } + + + public static class TestBean { + + private String name; + + public TestBean(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + } + + + public static class CustomResolver implements AutowireCandidateResolver { + + public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) { + if (!bdHolder.getBeanDefinition().isAutowireCandidate()) { + return false; + } + if (!bdHolder.getBeanName().matches("[a-z-]+")) { + return false; + } + if (bdHolder.getBeanDefinition().getAttribute("priority").equals("1")) { + return true; + } + return false; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/MyRequired.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/MyRequired.java new file mode 100644 index 00000000000..94d898d961a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/MyRequired.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2006 the original author 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.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +/** + * @author Rob Harrop + * @since 2.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface MyRequired { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessorTests.java new file mode 100644 index 00000000000..0dddcb3e977 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessorTests.java @@ -0,0 +1,80 @@ +/* + * Copyright 2002-2006 the original author 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.annotation; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Rob Harrop + * @since 2.0 + */ +public class RequiredAnnotationBeanPostProcessorTests extends TestCase { + + public void testWithRequiredPropertyOmitted() throws Exception { + try { + new ClassPathXmlApplicationContext("requiredWithOneRequiredPropertyOmitted.xml", getClass()); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + String message = ex.getCause().getMessage(); + assertTrue(message.indexOf("Property") > -1); + assertTrue(message.indexOf("age") > -1); + assertTrue(message.indexOf("testBean") > -1); + } + } + + public void testWithThreeRequiredPropertiesOmitted() throws Exception { + try { + new ClassPathXmlApplicationContext("requiredWithThreeRequiredPropertiesOmitted.xml", getClass()); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + String message = ex.getCause().getMessage(); + assertTrue(message.indexOf("Properties") > -1); + assertTrue(message.indexOf("age") > -1); + assertTrue(message.indexOf("favouriteColour") > -1); + assertTrue(message.indexOf("jobTitle") > -1); + assertTrue(message.indexOf("testBean") > -1); + } + } + + public void testWithOnlyRequiredPropertiesSpecified() throws Exception { + ApplicationContext context = + new ClassPathXmlApplicationContext("requiredWithAllRequiredPropertiesProvided.xml", getClass()); + RequiredTestBean bean = (RequiredTestBean) context.getBean("testBean"); + assertEquals(24, bean.getAge()); + assertEquals("Blue", bean.getFavouriteColour()); + } + + public void testWithCustomAnnotation() throws Exception { + try { + new ClassPathXmlApplicationContext("requiredWithCustomAnnotation.xml", getClass()); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + String message = ex.getCause().getMessage(); + assertTrue(message.indexOf("Property") > -1); + assertTrue(message.indexOf("name") > -1); + assertTrue(message.indexOf("testBean") > -1); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/RequiredTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/RequiredTestBean.java new file mode 100644 index 00000000000..ef78b1c17ff --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/RequiredTestBean.java @@ -0,0 +1,82 @@ +/* + * Copyright 2002-2006 the original author 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.annotation; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.BeanNameAware; + +/** + * @author Rob Harrop + * @since 2.0 + */ +public class RequiredTestBean implements BeanNameAware, BeanFactoryAware { + + private String name; + + private int age; + + private String favouriteColour; + + private String jobTitle; + + + public int getAge() { + return age; + } + + @Required + public void setAge(int age) { + this.age = age; + } + + public String getName() { + return name; + } + + @MyRequired + public void setName(String name) { + this.name = name; + } + + public String getFavouriteColour() { + return favouriteColour; + } + + @Required + public void setFavouriteColour(String favouriteColour) { + this.favouriteColour = favouriteColour; + } + + public String getJobTitle() { + return jobTitle; + } + + @Required + public void setJobTitle(String jobTitle) { + this.jobTitle = jobTitle; + } + + @Required + public void setBeanName(String name) { + } + + @Required + public void setBeanFactory(BeanFactory beanFactory) { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/customAutowireConfigurer.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/customAutowireConfigurer.xml new file mode 100644 index 00000000000..3e5e8fa5ae6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/customAutowireConfigurer.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithAllRequiredPropertiesProvided.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithAllRequiredPropertiesProvided.xml new file mode 100644 index 00000000000..93e04df03b5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithAllRequiredPropertiesProvided.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithCustomAnnotation.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithCustomAnnotation.xml new file mode 100644 index 00000000000..a643c8917a2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithCustomAnnotation.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithOneRequiredPropertyOmitted.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithOneRequiredPropertyOmitted.xml new file mode 100644 index 00000000000..3eb2e3c2e37 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithOneRequiredPropertyOmitted.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithThreeRequiredPropertiesOmitted.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithThreeRequiredPropertiesOmitted.xml new file mode 100644 index 00000000000..872361c5f4b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/annotation/requiredWithThreeRequiredPropertiesOmitted.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/MethodInvokingFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/MethodInvokingFactoryBeanTests.java deleted file mode 100644 index 7ef5d085704..00000000000 --- a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/MethodInvokingFactoryBeanTests.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright 2002-2008 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.beans.factory.config; - -import java.util.ArrayList; - -import junit.framework.TestCase; - -import org.springframework.beans.propertyeditors.StringTrimmerEditor; -import org.springframework.beans.support.ArgumentConvertingMethodInvoker; -import org.springframework.util.MethodInvoker; -import org.springframework.util.MethodInvokerTests; - -/** - * @author Colin Sampaleanu - * @author Juergen Hoeller - * @since 21.11.2003 - */ -public class MethodInvokingFactoryBeanTests extends TestCase { - - public void testParameterValidation() throws Exception { - String validationError = "improper validation of input properties"; - - // assert that only static OR non static are set, but not both or none - MethodInvokingFactoryBean mcfb = new MethodInvokingFactoryBean(); - try { - mcfb.afterPropertiesSet(); - fail(validationError); - } - catch (IllegalArgumentException ex) { - // expected - } - - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetObject(this); - mcfb.setTargetMethod("whatever"); - try { - mcfb.afterPropertiesSet(); - fail(validationError); - } - catch (NoSuchMethodException ex) { - // expected - } - - // bogus static method - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); - mcfb.setTargetMethod("some.bogus.Method.name"); - try { - mcfb.afterPropertiesSet(); - fail(validationError); - } - catch (NoSuchMethodException ex) { - // expected - } - - // bogus static method - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); - mcfb.setTargetMethod("method1"); - try { - mcfb.afterPropertiesSet(); - fail(validationError); - } - catch (IllegalArgumentException ex) { - // expected - } - - // missing method - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetObject(this); - try { - mcfb.afterPropertiesSet(); - fail(validationError); - } - catch (IllegalArgumentException ex) { - // expected - } - - // bogus method - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetObject(this); - mcfb.setTargetMethod("bogus"); - try { - mcfb.afterPropertiesSet(); - fail(validationError); - } - catch (NoSuchMethodException ex) { - // expected - } - - // static method - MethodInvokerTests.TestClass1._staticField1 = 0; - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); - mcfb.setTargetMethod("staticMethod1"); - mcfb.afterPropertiesSet(); - - // non-static method - MethodInvokerTests.TestClass1 tc1 = new MethodInvokerTests.TestClass1(); - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetObject(tc1); - mcfb.setTargetMethod("method1"); - mcfb.afterPropertiesSet(); - } - - public void testGetObjectType() throws Exception { - MethodInvokerTests.TestClass1 tc1 = new MethodInvokerTests.TestClass1(); - MethodInvokingFactoryBean mcfb = new MethodInvokingFactoryBean(); - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetObject(tc1); - mcfb.setTargetMethod("method1"); - mcfb.afterPropertiesSet(); - assertTrue(int.class.equals(mcfb.getObjectType())); - - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); - mcfb.setTargetMethod("voidRetvalMethod"); - mcfb.afterPropertiesSet(); - Class objType = mcfb.getObjectType(); - assertTrue(objType.equals(void.class)); - - // verify that we can call a method with args that are subtypes of the - // target method arg types - MethodInvokerTests.TestClass1._staticField1 = 0; - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); - mcfb.setTargetMethod("supertypes"); - mcfb.setArguments(new Object[] {new ArrayList(), new ArrayList(), "hello"}); - mcfb.afterPropertiesSet(); - mcfb.getObjectType(); - - // fail on improper argument types at afterPropertiesSet - mcfb = new MethodInvokingFactoryBean(); - mcfb.registerCustomEditor(String.class, new StringTrimmerEditor(false)); - mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); - mcfb.setTargetMethod("supertypes"); - mcfb.setArguments(new Object[] {"1", new Object()}); - try { - mcfb.afterPropertiesSet(); - fail("Should have thrown NoSuchMethodException"); - } - catch (NoSuchMethodException ex) { - // expected - } - } - - public void testGetObject() throws Exception { - // singleton, non-static - MethodInvokerTests.TestClass1 tc1 = new MethodInvokerTests.TestClass1(); - MethodInvokingFactoryBean mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetObject(tc1); - mcfb.setTargetMethod("method1"); - mcfb.afterPropertiesSet(); - Integer i = (Integer) mcfb.getObject(); - assertEquals(1, i.intValue()); - i = (Integer) mcfb.getObject(); - assertEquals(1, i.intValue()); - - // non-singleton, non-static - tc1 = new MethodInvokerTests.TestClass1(); - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetObject(tc1); - mcfb.setTargetMethod("method1"); - mcfb.setSingleton(false); - mcfb.afterPropertiesSet(); - i = (Integer) mcfb.getObject(); - assertEquals(1, i.intValue()); - i = (Integer) mcfb.getObject(); - assertEquals(2, i.intValue()); - - // singleton, static - MethodInvokerTests.TestClass1._staticField1 = 0; - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); - mcfb.setTargetMethod("staticMethod1"); - mcfb.afterPropertiesSet(); - i = (Integer) mcfb.getObject(); - assertEquals(1, i.intValue()); - i = (Integer) mcfb.getObject(); - assertEquals(1, i.intValue()); - - // non-singleton, static - MethodInvokerTests.TestClass1._staticField1 = 0; - mcfb = new MethodInvokingFactoryBean(); - mcfb.setStaticMethod("org.springframework.util.MethodInvokerTests$TestClass1.staticMethod1"); - mcfb.setSingleton(false); - mcfb.afterPropertiesSet(); - i = (Integer) mcfb.getObject(); - assertEquals(1, i.intValue()); - i = (Integer) mcfb.getObject(); - assertEquals(2, i.intValue()); - - // void return value - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); - mcfb.setTargetMethod("voidRetvalMethod"); - mcfb.afterPropertiesSet(); - assertNull(mcfb.getObject()); - - // now see if we can match methods with arguments that have supertype arguments - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); - mcfb.setTargetMethod("supertypes"); - mcfb.setArguments(new Object[] {new ArrayList(), new ArrayList(), "hello"}); - // should pass - mcfb.afterPropertiesSet(); - } - - public void testArgumentConversion() throws Exception { - MethodInvokingFactoryBean mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); - mcfb.setTargetMethod("supertypes"); - mcfb.setArguments(new Object[] {new ArrayList(), new ArrayList(), "hello", "bogus"}); - try { - mcfb.afterPropertiesSet(); - fail("Matched method with wrong number of args"); - } - catch (NoSuchMethodException ex) { - // expected - } - - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); - mcfb.setTargetMethod("supertypes"); - mcfb.setArguments(new Object[] {new Integer(1), new Object()}); - try { - mcfb.afterPropertiesSet(); - mcfb.getObject(); - fail("Should have failed on getObject with mismatched argument types"); - } - catch (NoSuchMethodException ex) { - // expected - } - - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); - mcfb.setTargetMethod("supertypes2"); - mcfb.setArguments(new Object[] {new ArrayList(), new ArrayList(), "hello", "bogus"}); - mcfb.afterPropertiesSet(); - assertEquals("hello", mcfb.getObject()); - - mcfb = new MethodInvokingFactoryBean(); - mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); - mcfb.setTargetMethod("supertypes2"); - mcfb.setArguments(new Object[] {new ArrayList(), new ArrayList(), new Object()}); - try { - mcfb.afterPropertiesSet(); - fail("Matched method when shouldn't have matched"); - } - catch (NoSuchMethodException ex) { - // expected - } - } - - public void testInvokeWithNullArgument() throws Exception { - MethodInvoker methodInvoker = new MethodInvoker(); - methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); - methodInvoker.setTargetMethod("nullArgument"); - methodInvoker.setArguments(new Object[] {null}); - methodInvoker.prepare(); - methodInvoker.invoke(); - } - - public void testInvokeWithIntArgument() throws Exception { - ArgumentConvertingMethodInvoker methodInvoker = new ArgumentConvertingMethodInvoker(); - methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); - methodInvoker.setTargetMethod("intArgument"); - methodInvoker.setArguments(new Object[] {new Integer(5)}); - methodInvoker.prepare(); - methodInvoker.invoke(); - - methodInvoker = new ArgumentConvertingMethodInvoker(); - methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); - methodInvoker.setTargetMethod("intArgument"); - methodInvoker.setArguments(new Object[] {"5"}); - methodInvoker.prepare(); - methodInvoker.invoke(); - } - - public void testInvokeWithIntArguments() throws Exception { - ArgumentConvertingMethodInvoker methodInvoker = new ArgumentConvertingMethodInvoker(); - methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); - methodInvoker.setTargetMethod("intArguments"); - methodInvoker.setArguments(new Object[] {new Integer[] {new Integer(5), new Integer(10)}}); - methodInvoker.prepare(); - methodInvoker.invoke(); - - methodInvoker = new ArgumentConvertingMethodInvoker(); - methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); - methodInvoker.setTargetMethod("intArguments"); - methodInvoker.setArguments(new Object[] {new String[] {"5", "10"}}); - methodInvoker.prepare(); - methodInvoker.invoke(); - - methodInvoker = new ArgumentConvertingMethodInvoker(); - methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); - methodInvoker.setTargetMethod("intArguments"); - methodInvoker.setArguments(new Integer[] {new Integer(5), new Integer(10)}); - methodInvoker.prepare(); - methodInvoker.invoke(); - - methodInvoker = new ArgumentConvertingMethodInvoker(); - methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); - methodInvoker.setTargetMethod("intArguments"); - methodInvoker.setArguments(new String[] {"5", "10"}); - methodInvoker.prepare(); - methodInvoker.invoke(); - - methodInvoker = new ArgumentConvertingMethodInvoker(); - methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); - methodInvoker.setTargetMethod("intArguments"); - methodInvoker.setArguments(new Object[] {new Integer(5), new Integer(10)}); - methodInvoker.prepare(); - methodInvoker.invoke(); - - methodInvoker = new ArgumentConvertingMethodInvoker(); - methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); - methodInvoker.setTargetMethod("intArguments"); - methodInvoker.setArguments(new Object[] {"5", "10"}); - methodInvoker.prepare(); - methodInvoker.invoke(); - } - -} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/GenericBeanFactoryAccessorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/GenericBeanFactoryAccessorTests.java new file mode 100644 index 00000000000..7a0f7a37fee --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/GenericBeanFactoryAccessorTests.java @@ -0,0 +1,78 @@ +/* + * Copyright 2002-2006 the original author 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.generic; + +import junit.framework.TestCase; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.beans.TestBean; +import org.springframework.core.io.ClassPathResource; +import org.springframework.test.AssertThrows; + +import java.util.Map; + +/** + * @author Rob Harrop + * @see 2.0 + */ +public class GenericBeanFactoryAccessorTests extends TestCase { + + private GenericBeanFactoryAccessor beanFactoryAccessor; + + protected void setUp() throws Exception { + XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("genericBeanFactoryAccessorTests.xml", getClass())); + this.beanFactoryAccessor = new GenericBeanFactoryAccessor(beanFactory); + } + + public void testGetBean() throws Exception { + TestBean testBean = this.beanFactoryAccessor.getBean("testBean"); + assertNotNull("TestBean should not be null", testBean); + } + + public void testGetBeanWithType() throws Exception { + TestBean testBean = this.beanFactoryAccessor.getBean("testBean", TestBean.class); + assertNotNull("TestBean should not be null", testBean); + } + + public void testGetBeanFails() throws Exception { + new AssertThrows(ClassCastException.class) { + public void test() throws Exception { + Integer bean = beanFactoryAccessor.getBean("testBean"); + } + }.runTest(); + } + + public void testGetBeansOfType() throws Exception { + Map beansOfType = this.beanFactoryAccessor.getBeansOfType(TestBean.class); + assertEquals(3, beansOfType.size()); + assertNotNull(beansOfType.get("testBean")); + assertNotNull(beansOfType.get("otherTestBean")); + assertNotNull(beansOfType.get("prototypeTestBean")); + } + + public void testGetBeansOfTypeExtended() throws Exception { + Map beansOfType = this.beanFactoryAccessor.getBeansOfType(TestBean.class, false, false); + assertEquals(2, beansOfType.size()); + assertNotNull(beansOfType.get("testBean")); + assertNotNull(beansOfType.get("otherTestBean")); + } + + public void testGetBeansWithAnnotation() throws Exception { + Map beansWithAnnotation = this.beanFactoryAccessor.getBeansWithAnnotation(MyAnnotation.class); + assertEquals(1, beansWithAnnotation.size()); + assertNotNull(beansWithAnnotation.get("annotatedBean")); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/MyAnnotation.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/MyAnnotation.java new file mode 100644 index 00000000000..fb4813f361c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/MyAnnotation.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2006 the original author 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.generic; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +/** + * @author Rob Harrop + * @since 2.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface MyAnnotation { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/SomeAnnotatedBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/SomeAnnotatedBean.java new file mode 100644 index 00000000000..2b81ad4faf0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/SomeAnnotatedBean.java @@ -0,0 +1,26 @@ +/* + * Copyright 2002-2006 the original author 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.generic; + +/** + * @author Rob Harrop + * @since 2.0 + */ +@MyAnnotation +public class SomeAnnotatedBean { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/genericBeanFactoryAccessorTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/genericBeanFactoryAccessorTests.xml new file mode 100644 index 00000000000..9e6934904e4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/generic/genericBeanFactoryAccessorTests.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/serviceloader/ServiceLoaderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/serviceloader/ServiceLoaderTests.java new file mode 100644 index 00000000000..4ea7f6dfd0a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/serviceloader/ServiceLoaderTests.java @@ -0,0 +1,76 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.serviceloader; + +import java.util.List; +import java.util.ServiceLoader; + +import javax.xml.parsers.DocumentBuilderFactory; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.core.JdkVersion; + +/** + * @author Juergen Hoeller + */ +public class ServiceLoaderTests extends TestCase { + + public void testServiceLoaderFactoryBean() { + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_16 || + !ServiceLoader.load(DocumentBuilderFactory.class).iterator().hasNext()){ + return; + } + + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(ServiceLoaderFactoryBean.class); + bd.getPropertyValues().addPropertyValue("serviceType", DocumentBuilderFactory.class.getName()); + bf.registerBeanDefinition("service", bd); + ServiceLoader serviceLoader = (ServiceLoader) bf.getBean("service"); + assertTrue(serviceLoader.iterator().next() instanceof DocumentBuilderFactory); + } + + public void testServiceFactoryBean() { + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_16 || + !ServiceLoader.load(DocumentBuilderFactory.class).iterator().hasNext()){ + return; + } + + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(ServiceFactoryBean.class); + bd.getPropertyValues().addPropertyValue("serviceType", DocumentBuilderFactory.class.getName()); + bf.registerBeanDefinition("service", bd); + assertTrue(bf.getBean("service") instanceof DocumentBuilderFactory); + } + + public void testServiceListFactoryBean() { + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_16 || + !ServiceLoader.load(DocumentBuilderFactory.class).iterator().hasNext()){ + return; + } + + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(ServiceListFactoryBean.class); + bd.getPropertyValues().addPropertyValue("serviceType", DocumentBuilderFactory.class.getName()); + bf.registerBeanDefinition("service", bd); + List serviceList = (List) bf.getBean("service"); + assertTrue(serviceList.get(0) instanceof DocumentBuilderFactory); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java new file mode 100644 index 00000000000..37782debb05 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java @@ -0,0 +1,595 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import junit.framework.TestCase; + +import org.springframework.beans.GenericBean; +import org.springframework.beans.GenericIntegerBean; +import org.springframework.beans.GenericSetOfIntegerBean; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.beans.propertyeditors.CustomNumberEditor; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.UrlResource; + +/** + * @author Juergen Hoeller + * @since 20.01.2006 + */ +public class BeanFactoryGenericsTests extends TestCase { + + public void testGenericSetProperty() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + + Set input = new HashSet(); + input.add("4"); + input.add("5"); + rbd.getPropertyValues().addPropertyValue("integerSet", input); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertTrue(gb.getIntegerSet().contains(new Integer(4))); + assertTrue(gb.getIntegerSet().contains(new Integer(5))); + } + + public void testGenericListProperty() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + + List input = new ArrayList(); + input.add("http://localhost:8080"); + input.add("http://localhost:9090"); + rbd.getPropertyValues().addPropertyValue("resourceList", input); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertEquals(new UrlResource("http://localhost:8080"), gb.getResourceList().get(0)); + assertEquals(new UrlResource("http://localhost:9090"), gb.getResourceList().get(1)); + } + + public void testGenericListPropertyWithAutowiring() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerSingleton("resource1", new UrlResource("http://localhost:8080")); + bf.registerSingleton("resource2", new UrlResource("http://localhost:9090")); + + RootBeanDefinition rbd = new RootBeanDefinition(GenericIntegerBean.class, RootBeanDefinition.AUTOWIRE_BY_TYPE); + bf.registerBeanDefinition("genericBean", rbd); + GenericIntegerBean gb = (GenericIntegerBean) bf.getBean("genericBean"); + + assertEquals(new UrlResource("http://localhost:8080"), gb.getResourceList().get(0)); + assertEquals(new UrlResource("http://localhost:9090"), gb.getResourceList().get(1)); + } + + public void testGenericListPropertyWithOptionalAutowiring() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class, RootBeanDefinition.AUTOWIRE_BY_TYPE); + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertNull(gb.getResourceList()); + } + + public void testGenericMapProperty() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + + Map input = new HashMap(); + input.put("4", "5"); + input.put("6", "7"); + rbd.getPropertyValues().addPropertyValue("shortMap", input); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertEquals(new Integer(5), gb.getShortMap().get(new Short("4"))); + assertEquals(new Integer(7), gb.getShortMap().get(new Short("6"))); + } + + public void testGenericListOfArraysProperty() throws MalformedURLException { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("genericBeanTests.xml", getClass())); + GenericBean gb = (GenericBean) bf.getBean("listOfArrays"); + + assertEquals(1, gb.getListOfArrays().size()); + String[] array = gb.getListOfArrays().get(0); + assertEquals(2, array.length); + assertEquals("value1", array[0]); + assertEquals("value2", array[1]); + } + + + public void testGenericSetConstructor() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + + Set input = new HashSet(); + input.add("4"); + input.add("5"); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertTrue(gb.getIntegerSet().contains(new Integer(4))); + assertTrue(gb.getIntegerSet().contains(new Integer(5))); + } + + public void testGenericSetConstructorWithAutowiring() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerSingleton("integer1", new Integer(4)); + bf.registerSingleton("integer2", new Integer(5)); + + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertTrue(gb.getIntegerSet().contains(new Integer(4))); + assertTrue(gb.getIntegerSet().contains(new Integer(5))); + } + + public void testGenericSetConstructorWithOptionalAutowiring() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertNull(gb.getIntegerSet()); + } + + public void testGenericSetListConstructor() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + + Set input = new HashSet(); + input.add("4"); + input.add("5"); + List input2 = new ArrayList(); + input2.add("http://localhost:8080"); + input2.add("http://localhost:9090"); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input2); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertTrue(gb.getIntegerSet().contains(new Integer(4))); + assertTrue(gb.getIntegerSet().contains(new Integer(5))); + assertEquals(new UrlResource("http://localhost:8080"), gb.getResourceList().get(0)); + assertEquals(new UrlResource("http://localhost:9090"), gb.getResourceList().get(1)); + } + + public void testGenericSetListConstructorWithAutowiring() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerSingleton("integer1", new Integer(4)); + bf.registerSingleton("integer2", new Integer(5)); + bf.registerSingleton("resource1", new UrlResource("http://localhost:8080")); + bf.registerSingleton("resource2", new UrlResource("http://localhost:9090")); + + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertTrue(gb.getIntegerSet().contains(new Integer(4))); + assertTrue(gb.getIntegerSet().contains(new Integer(5))); + assertEquals(new UrlResource("http://localhost:8080"), gb.getResourceList().get(0)); + assertEquals(new UrlResource("http://localhost:9090"), gb.getResourceList().get(1)); + } + + public void testGenericSetListConstructorWithOptionalAutowiring() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerSingleton("resource1", new UrlResource("http://localhost:8080")); + bf.registerSingleton("resource2", new UrlResource("http://localhost:9090")); + + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertNull(gb.getIntegerSet()); + assertNull(gb.getResourceList()); + } + + public void testGenericSetMapConstructor() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + + Set input = new HashSet(); + input.add("4"); + input.add("5"); + Map input2 = new HashMap(); + input2.put("4", "5"); + input2.put("6", "7"); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input2); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertTrue(gb.getIntegerSet().contains(new Integer(4))); + assertTrue(gb.getIntegerSet().contains(new Integer(5))); + assertEquals(new Integer(5), gb.getShortMap().get(new Short("4"))); + assertEquals(new Integer(7), gb.getShortMap().get(new Short("6"))); + } + + public void testGenericMapResourceConstructor() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + + Map input = new HashMap(); + input.put("4", "5"); + input.put("6", "7"); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + rbd.getConstructorArgumentValues().addGenericArgumentValue("http://localhost:8080"); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertEquals(new Integer(5), gb.getShortMap().get(new Short("4"))); + assertEquals(new Integer(7), gb.getShortMap().get(new Short("6"))); + assertEquals(new UrlResource("http://localhost:8080"), gb.getResourceList().get(0)); + } + + public void testGenericMapMapConstructor() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + + Map input = new HashMap(); + input.put("1", "0"); + input.put("2", "3"); + Map input2 = new HashMap(); + input2.put("4", "5"); + input2.put("6", "7"); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input2); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertNotSame(gb.getPlainMap(), gb.getShortMap()); + assertEquals(2, gb.getPlainMap().size()); + assertEquals("0", gb.getPlainMap().get("1")); + assertEquals("3", gb.getPlainMap().get("2")); + assertEquals(2, gb.getShortMap().size()); + assertEquals(new Integer(5), gb.getShortMap().get(new Short("4"))); + assertEquals(new Integer(7), gb.getShortMap().get(new Short("6"))); + } + + public void testGenericMapMapConstructorWithSameRefAndConversion() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + + Map input = new HashMap(); + input.put("1", "0"); + input.put("2", "3"); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertNotSame(gb.getPlainMap(), gb.getShortMap()); + assertEquals(2, gb.getPlainMap().size()); + assertEquals("0", gb.getPlainMap().get("1")); + assertEquals("3", gb.getPlainMap().get("2")); + assertEquals(2, gb.getShortMap().size()); + assertEquals(new Integer(0), gb.getShortMap().get(new Short("1"))); + assertEquals(new Integer(3), gb.getShortMap().get(new Short("2"))); + } + + public void testGenericMapMapConstructorWithSameRefAndNoConversion() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + + Map input = new HashMap(); + input.put(new Short((short) 1), new Integer(0)); + input.put(new Short((short) 2), new Integer(3)); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertSame(gb.getPlainMap(), gb.getShortMap()); + assertEquals(2, gb.getShortMap().size()); + assertEquals(new Integer(0), gb.getShortMap().get(new Short("1"))); + assertEquals(new Integer(3), gb.getShortMap().get(new Short("2"))); + } + + public void testGenericMapWithKeyTypeConstructor() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + + Map input = new HashMap(); + input.put("4", "5"); + input.put("6", "7"); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertEquals("5", gb.getLongMap().get(new Long("4"))); + assertEquals("7", gb.getLongMap().get(new Long("6"))); + } + + public void testGenericMapWithCollectionValueConstructor() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerCustomEditor(Number.class, new CustomNumberEditor(Integer.class, false)); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + + Map input = new HashMap(); + HashSet value1 = new HashSet(); + value1.add(new Integer(1)); + input.put("1", value1); + ArrayList value2 = new ArrayList(); + value2.add(Boolean.TRUE); + input.put("2", value2); + rbd.getConstructorArgumentValues().addGenericArgumentValue(Boolean.TRUE); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertTrue(gb.getCollectionMap().get(new Integer(1)) instanceof HashSet); + assertTrue(gb.getCollectionMap().get(new Integer(2)) instanceof ArrayList); + } + + + public void testGenericSetFactoryMethod() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + rbd.setFactoryMethodName("createInstance"); + + Set input = new HashSet(); + input.add("4"); + input.add("5"); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertTrue(gb.getIntegerSet().contains(new Integer(4))); + assertTrue(gb.getIntegerSet().contains(new Integer(5))); + } + + public void testGenericSetListFactoryMethod() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + rbd.setFactoryMethodName("createInstance"); + + Set input = new HashSet(); + input.add("4"); + input.add("5"); + List input2 = new ArrayList(); + input2.add("http://localhost:8080"); + input2.add("http://localhost:9090"); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input2); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertTrue(gb.getIntegerSet().contains(new Integer(4))); + assertTrue(gb.getIntegerSet().contains(new Integer(5))); + assertEquals(new UrlResource("http://localhost:8080"), gb.getResourceList().get(0)); + assertEquals(new UrlResource("http://localhost:9090"), gb.getResourceList().get(1)); + } + + public void testGenericSetMapFactoryMethod() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + rbd.setFactoryMethodName("createInstance"); + + Set input = new HashSet(); + input.add("4"); + input.add("5"); + Map input2 = new HashMap(); + input2.put("4", "5"); + input2.put("6", "7"); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input2); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertTrue(gb.getIntegerSet().contains(new Integer(4))); + assertTrue(gb.getIntegerSet().contains(new Integer(5))); + assertEquals(new Integer(5), gb.getShortMap().get(new Short("4"))); + assertEquals(new Integer(7), gb.getShortMap().get(new Short("6"))); + } + + public void testGenericMapResourceFactoryMethod() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + rbd.setFactoryMethodName("createInstance"); + + Map input = new HashMap(); + input.put("4", "5"); + input.put("6", "7"); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + rbd.getConstructorArgumentValues().addGenericArgumentValue("http://localhost:8080"); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertEquals(new Integer(5), gb.getShortMap().get(new Short("4"))); + assertEquals(new Integer(7), gb.getShortMap().get(new Short("6"))); + assertEquals(new UrlResource("http://localhost:8080"), gb.getResourceList().get(0)); + } + + public void testGenericMapMapFactoryMethod() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + rbd.setFactoryMethodName("createInstance"); + + Map input = new HashMap(); + input.put("1", "0"); + input.put("2", "3"); + Map input2 = new HashMap(); + input2.put("4", "5"); + input2.put("6", "7"); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input2); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertEquals("0", gb.getPlainMap().get("1")); + assertEquals("3", gb.getPlainMap().get("2")); + assertEquals(new Integer(5), gb.getShortMap().get(new Short("4"))); + assertEquals(new Integer(7), gb.getShortMap().get(new Short("6"))); + } + + public void testGenericMapWithKeyTypeFactoryMethod() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + rbd.setFactoryMethodName("createInstance"); + + Map input = new HashMap(); + input.put("4", "5"); + input.put("6", "7"); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertEquals("5", gb.getLongMap().get(new Long("4"))); + assertEquals("7", gb.getLongMap().get(new Long("6"))); + } + + public void testGenericMapWithCollectionValueFactoryMethod() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerCustomEditor(Number.class, new CustomNumberEditor(Integer.class, false)); + RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); + rbd.setFactoryMethodName("createInstance"); + + Map input = new HashMap(); + HashSet value1 = new HashSet(); + value1.add(new Integer(1)); + input.put("1", value1); + ArrayList value2 = new ArrayList(); + value2.add(Boolean.TRUE); + input.put("2", value2); + rbd.getConstructorArgumentValues().addGenericArgumentValue(Boolean.TRUE); + rbd.getConstructorArgumentValues().addGenericArgumentValue(input); + + bf.registerBeanDefinition("genericBean", rbd); + GenericBean gb = (GenericBean) bf.getBean("genericBean"); + + assertTrue(gb.getCollectionMap().get(new Integer(1)) instanceof HashSet); + assertTrue(gb.getCollectionMap().get(new Integer(2)) instanceof ArrayList); + } + + public void testGenericListBean() throws Exception { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("genericBeanTests.xml", getClass())); + List list = (List) bf.getBean("list"); + assertEquals(1, list.size()); + assertEquals(new URL("http://localhost:8080"), list.get(0)); + } + + public void testGenericSetBean() throws Exception { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("genericBeanTests.xml", getClass())); + Set set = (Set) bf.getBean("set"); + assertEquals(1, set.size()); + assertEquals(new URL("http://localhost:8080"), set.iterator().next()); + } + + public void testGenericMapBean() throws Exception { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("genericBeanTests.xml", getClass())); + Map map = (Map) bf.getBean("map"); + assertEquals(1, map.size()); + assertEquals(new Integer(10), map.keySet().iterator().next()); + assertEquals(new URL("http://localhost:8080"), map.values().iterator().next()); + } + + public void testGenericallyTypedIntegerBean() throws Exception { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("genericBeanTests.xml", getClass())); + GenericIntegerBean gb = (GenericIntegerBean) bf.getBean("integerBean"); + assertEquals(new Integer(10), gb.getGenericProperty()); + assertEquals(new Integer(20), gb.getGenericListProperty().get(0)); + assertEquals(new Integer(30), gb.getGenericListProperty().get(1)); + } + + public void testGenericallyTypedSetOfIntegerBean() throws Exception { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("genericBeanTests.xml", getClass())); + GenericSetOfIntegerBean gb = (GenericSetOfIntegerBean) bf.getBean("setOfIntegerBean"); + assertEquals(new Integer(10), gb.getGenericProperty().iterator().next()); + assertEquals(new Integer(20), gb.getGenericListProperty().get(0).iterator().next()); + assertEquals(new Integer(30), gb.getGenericListProperty().get(1).iterator().next()); + } + + public void testSetBean() throws Exception { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("genericBeanTests.xml", getClass())); + UrlSet us = (UrlSet) bf.getBean("setBean"); + assertEquals(1, us.size()); + assertEquals(new URL("http://www.springframework.org"), us.iterator().next()); + } + + + public static class NamedUrlList extends LinkedList { + } + + + public static class NamedUrlSet extends HashSet { + } + + + public static class NamedUrlMap extends HashMap { + } + + + public static class CollectionDependentBean { + + public CollectionDependentBean(NamedUrlList list, NamedUrlSet set, NamedUrlMap map) { + assertEquals(1, list.size()); + assertEquals(1, set.size()); + assertEquals(1, map.size()); + } + } + + + public static class UrlSet extends HashSet { + + public UrlSet() { + super(); + } + + public UrlSet(Set urls) { + super(); + } + + public void setUrlNames(Set urlNames) throws MalformedURLException { + for (URI urlName : urlNames) { + add(urlName.toURL()); + } + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireBeanFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireBeanFactoryTests.java new file mode 100644 index 00000000000..334e89b5c95 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireBeanFactoryTests.java @@ -0,0 +1,234 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.config.ConstructorArgumentValues; +import org.springframework.beans.factory.config.DependencyDescriptor; +import org.springframework.core.LocalVariableTableParameterNameDiscoverer; +import org.springframework.core.MethodParameter; +import org.springframework.util.ClassUtils; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +public class QualifierAnnotationAutowireBeanFactoryTests extends TestCase { + + private static final String JUERGEN = "juergen"; + + private static final String MARK = "mark"; + + + public void testAutowireCandidateDefaultWithIrrelevantDescriptor() throws Exception { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + ConstructorArgumentValues cavs = new ConstructorArgumentValues(); + cavs.addGenericArgumentValue(JUERGEN); + RootBeanDefinition rbd = new RootBeanDefinition(Person.class, cavs, null); + lbf.registerBeanDefinition(JUERGEN, rbd); + assertTrue(lbf.isAutowireCandidate(JUERGEN, null)); + assertTrue(lbf.isAutowireCandidate(JUERGEN, + new DependencyDescriptor(Person.class.getDeclaredField("name"), false))); + assertTrue(lbf.isAutowireCandidate(JUERGEN, + new DependencyDescriptor(Person.class.getDeclaredField("name"), true))); + } + + public void testAutowireCandidateExplicitlyFalseWithIrrelevantDescriptor() throws Exception { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + ConstructorArgumentValues cavs = new ConstructorArgumentValues(); + cavs.addGenericArgumentValue(JUERGEN); + RootBeanDefinition rbd = new RootBeanDefinition(Person.class, cavs, null); + rbd.setAutowireCandidate(false); + lbf.registerBeanDefinition(JUERGEN, rbd); + assertFalse(lbf.isAutowireCandidate(JUERGEN, null)); + assertFalse(lbf.isAutowireCandidate(JUERGEN, + new DependencyDescriptor(Person.class.getDeclaredField("name"), false))); + assertFalse(lbf.isAutowireCandidate(JUERGEN, + new DependencyDescriptor(Person.class.getDeclaredField("name"), true))); + } + + public void testAutowireCandidateWithFieldDescriptor() throws Exception { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + person1.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); + lbf.registerBeanDefinition(JUERGEN, person1); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + lbf.registerBeanDefinition(MARK, person2); + DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor( + QualifiedTestBean.class.getDeclaredField("qualified"), false); + DependencyDescriptor nonqualifiedDescriptor = new DependencyDescriptor( + QualifiedTestBean.class.getDeclaredField("nonqualified"), false); + assertTrue(lbf.isAutowireCandidate(JUERGEN, null)); + assertTrue(lbf.isAutowireCandidate(JUERGEN, nonqualifiedDescriptor)); + assertTrue(lbf.isAutowireCandidate(JUERGEN, qualifiedDescriptor)); + assertTrue(lbf.isAutowireCandidate(MARK, null)); + assertTrue(lbf.isAutowireCandidate(MARK, nonqualifiedDescriptor)); + assertFalse(lbf.isAutowireCandidate(MARK, qualifiedDescriptor)); + } + + public void testAutowireCandidateExplicitlyFalseWithFieldDescriptor() throws Exception { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + ConstructorArgumentValues cavs = new ConstructorArgumentValues(); + cavs.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); + person.setAutowireCandidate(false); + person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); + lbf.registerBeanDefinition(JUERGEN, person); + DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor( + QualifiedTestBean.class.getDeclaredField("qualified"), false); + DependencyDescriptor nonqualifiedDescriptor = new DependencyDescriptor( + QualifiedTestBean.class.getDeclaredField("nonqualified"), false); + assertFalse(lbf.isAutowireCandidate(JUERGEN, null)); + assertFalse(lbf.isAutowireCandidate(JUERGEN, nonqualifiedDescriptor)); + assertFalse(lbf.isAutowireCandidate(JUERGEN, qualifiedDescriptor)); + } + + public void testAutowireCandidateWithShortClassName() throws Exception { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + ConstructorArgumentValues cavs = new ConstructorArgumentValues(); + cavs.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); + person.addQualifier(new AutowireCandidateQualifier(ClassUtils.getShortName(TestQualifier.class))); + lbf.registerBeanDefinition(JUERGEN, person); + DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor( + QualifiedTestBean.class.getDeclaredField("qualified"), false); + DependencyDescriptor nonqualifiedDescriptor = new DependencyDescriptor( + QualifiedTestBean.class.getDeclaredField("nonqualified"), false); + assertTrue(lbf.isAutowireCandidate(JUERGEN, null)); + assertTrue(lbf.isAutowireCandidate(JUERGEN, nonqualifiedDescriptor)); + assertTrue(lbf.isAutowireCandidate(JUERGEN, qualifiedDescriptor)); + } + + public void testAutowireCandidateWithConstructorDescriptor() throws Exception { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + person1.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); + lbf.registerBeanDefinition(JUERGEN, person1); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + lbf.registerBeanDefinition(MARK, person2); + MethodParameter param = new MethodParameter(QualifiedTestBean.class.getDeclaredConstructor(Person.class), 0); + DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor(param, false); + param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); + assertEquals("tpb", param.getParameterName()); + assertTrue(lbf.isAutowireCandidate(JUERGEN, null)); + assertTrue(lbf.isAutowireCandidate(JUERGEN, qualifiedDescriptor)); + assertFalse(lbf.isAutowireCandidate(MARK, qualifiedDescriptor)); + } + + public void testAutowireCandidateWithMethodDescriptor() throws Exception { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + person1.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); + lbf.registerBeanDefinition(JUERGEN, person1); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + lbf.registerBeanDefinition(MARK, person2); + MethodParameter qualifiedParam = + new MethodParameter(QualifiedTestBean.class.getDeclaredMethod("autowireQualified", Person.class), 0); + MethodParameter nonqualifiedParam = + new MethodParameter(QualifiedTestBean.class.getDeclaredMethod("autowireNonqualified", Person.class), 0); + DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor(qualifiedParam, false); + DependencyDescriptor nonqualifiedDescriptor = new DependencyDescriptor(nonqualifiedParam, false); + qualifiedParam.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); + assertEquals("tpb", qualifiedParam.getParameterName()); + nonqualifiedParam.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); + assertEquals("tpb", nonqualifiedParam.getParameterName()); + assertTrue(lbf.isAutowireCandidate(JUERGEN, null)); + assertTrue(lbf.isAutowireCandidate(JUERGEN, nonqualifiedDescriptor)); + assertTrue(lbf.isAutowireCandidate(JUERGEN, qualifiedDescriptor)); + assertTrue(lbf.isAutowireCandidate(MARK, null)); + assertTrue(lbf.isAutowireCandidate(MARK, nonqualifiedDescriptor)); + assertFalse(lbf.isAutowireCandidate(MARK, qualifiedDescriptor)); + } + + public void testAutowireCandidateWithMultipleCandidatesDescriptor() throws Exception { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + person1.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); + lbf.registerBeanDefinition(JUERGEN, person1); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + person2.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); + lbf.registerBeanDefinition(MARK, person2); + DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor( + new MethodParameter(QualifiedTestBean.class.getDeclaredConstructor(Person.class), 0), + false); + assertTrue(lbf.isAutowireCandidate(JUERGEN, qualifiedDescriptor)); + assertTrue(lbf.isAutowireCandidate(MARK, qualifiedDescriptor)); + } + + + private static class QualifiedTestBean { + + @TestQualifier + private Person qualified; + + private Person nonqualified; + + public QualifiedTestBean(@TestQualifier Person tpb) { + } + + public void autowireQualified(@TestQualifier Person tpb) { + } + + public void autowireNonqualified(Person tpb) { + } + } + + + private static class Person { + + private String name; + + public Person(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + } + + + @Target({ElementType.FIELD, ElementType.PARAMETER}) + @Retention(RetentionPolicy.RUNTIME) + @Qualifier + private static @interface TestQualifier { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireContextTests.java new file mode 100644 index 00000000000..3bbf9a8d2d5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireContextTests.java @@ -0,0 +1,683 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.UnsatisfiedDependencyException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.config.ConstructorArgumentValues; +import org.springframework.context.annotation.AnnotationConfigUtils; +import org.springframework.context.support.GenericApplicationContext; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +public class QualifierAnnotationAutowireContextTests extends TestCase { + + private static final String JUERGEN = "juergen"; + + private static final String MARK = "mark"; + + + public void testAutowiredFieldWithSingleNonQualifiedCandidate() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs = new ConstructorArgumentValues(); + cavs.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); + context.registerBeanDefinition(JUERGEN, person); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedFieldTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + try { + context.refresh(); + fail("expected BeanCreationException"); + } + catch (BeanCreationException e) { + assertTrue(e.getRootCause() instanceof NoSuchBeanDefinitionException); + assertEquals("autowired", e.getBeanName()); + } + } + + public void testAutowiredMethodParameterWithSingleNonQualifiedCandidate() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs = new ConstructorArgumentValues(); + cavs.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); + context.registerBeanDefinition(JUERGEN, person); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedMethodParameterTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + try { + context.refresh(); + fail("expected BeanCreationException"); + } + catch (BeanCreationException e) { + assertTrue(e.getRootCause() instanceof NoSuchBeanDefinitionException); + assertEquals("autowired", e.getBeanName()); + } + } + + public void testAutowiredConstructorArgumentWithSingleNonQualifiedCandidate() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs = new ConstructorArgumentValues(); + cavs.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); + context.registerBeanDefinition(JUERGEN, person); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + try { + context.refresh(); + fail("expected BeanCreationException"); + } + catch (BeanCreationException e) { + assertTrue(e instanceof UnsatisfiedDependencyException); + assertEquals("autowired", e.getBeanName()); + } + } + + public void testAutowiredFieldWithSingleQualifiedCandidate() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs = new ConstructorArgumentValues(); + cavs.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); + person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); + context.registerBeanDefinition(JUERGEN, person); + context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + context.refresh(); + QualifiedFieldTestBean bean = (QualifiedFieldTestBean) context.getBean("autowired"); + assertEquals(JUERGEN, bean.getPerson().getName()); + } + + public void testAutowiredMethodParameterWithSingleQualifiedCandidate() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs = new ConstructorArgumentValues(); + cavs.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); + person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); + context.registerBeanDefinition(JUERGEN, person); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedMethodParameterTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + context.refresh(); + QualifiedMethodParameterTestBean bean = + (QualifiedMethodParameterTestBean) context.getBean("autowired"); + assertEquals(JUERGEN, bean.getPerson().getName()); + } + + public void testAutowiredMethodParameterWithStaticallyQualifiedCandidate() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs = new ConstructorArgumentValues(); + cavs.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person = new RootBeanDefinition(QualifiedPerson.class, cavs, null); + context.registerBeanDefinition(JUERGEN, person); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedMethodParameterTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + context.refresh(); + QualifiedMethodParameterTestBean bean = + (QualifiedMethodParameterTestBean) context.getBean("autowired"); + assertEquals(JUERGEN, bean.getPerson().getName()); + } + + public void testAutowiredConstructorArgumentWithSingleQualifiedCandidate() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs = new ConstructorArgumentValues(); + cavs.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); + person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); + context.registerBeanDefinition(JUERGEN, person); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + context.refresh(); + QualifiedConstructorArgumentTestBean bean = + (QualifiedConstructorArgumentTestBean) context.getBean("autowired"); + assertEquals(JUERGEN, bean.getPerson().getName()); + } + + public void testAutowiredFieldWithMultipleNonQualifiedCandidates() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + context.registerBeanDefinition(JUERGEN, person1); + context.registerBeanDefinition(MARK, person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedFieldTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + try { + context.refresh(); + fail("expected BeanCreationException"); + } + catch (BeanCreationException e) { + assertTrue(e.getRootCause() instanceof NoSuchBeanDefinitionException); + assertEquals("autowired", e.getBeanName()); + } + } + + public void testAutowiredMethodParameterWithMultipleNonQualifiedCandidates() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + context.registerBeanDefinition(JUERGEN, person1); + context.registerBeanDefinition(MARK, person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedMethodParameterTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + try { + context.refresh(); + fail("expected BeanCreationException"); + } + catch (BeanCreationException e) { + assertTrue(e.getRootCause() instanceof NoSuchBeanDefinitionException); + assertEquals("autowired", e.getBeanName()); + } + } + + public void testAutowiredConstructorArgumentWithMultipleNonQualifiedCandidates() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + context.registerBeanDefinition(JUERGEN, person1); + context.registerBeanDefinition(MARK, person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + try { + context.refresh(); + fail("expected BeanCreationException"); + } + catch (BeanCreationException e) { + assertTrue(e instanceof UnsatisfiedDependencyException); + assertEquals("autowired", e.getBeanName()); + } + } + + public void testAutowiredFieldResolvesQualifiedCandidate() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + person1.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + context.registerBeanDefinition(JUERGEN, person1); + context.registerBeanDefinition(MARK, person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedFieldTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + context.refresh(); + QualifiedFieldTestBean bean = (QualifiedFieldTestBean) context.getBean("autowired"); + assertEquals(JUERGEN, bean.getPerson().getName()); + } + + public void testAutowiredMethodParameterResolvesQualifiedCandidate() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + person1.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + context.registerBeanDefinition(JUERGEN, person1); + context.registerBeanDefinition(MARK, person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedMethodParameterTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + context.refresh(); + QualifiedMethodParameterTestBean bean = + (QualifiedMethodParameterTestBean) context.getBean("autowired"); + assertEquals(JUERGEN, bean.getPerson().getName()); + } + + public void testAutowiredConstructorArgumentResolvesQualifiedCandidate() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + person1.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + context.registerBeanDefinition(JUERGEN, person1); + context.registerBeanDefinition(MARK, person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + context.refresh(); + QualifiedConstructorArgumentTestBean bean = + (QualifiedConstructorArgumentTestBean) context.getBean("autowired"); + assertEquals(JUERGEN, bean.getPerson().getName()); + } + + public void testAutowiredFieldResolvesQualifiedCandidateWithDefaultValueAndNoValueOnBeanDefinition() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + // qualifier added, but includes no value + person1.addQualifier(new AutowireCandidateQualifier(TestQualifierWithDefaultValue.class)); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + context.registerBeanDefinition(JUERGEN, person1); + context.registerBeanDefinition(MARK, person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + context.refresh(); + QualifiedFieldWithDefaultValueTestBean bean = + (QualifiedFieldWithDefaultValueTestBean) context.getBean("autowired"); + assertEquals(JUERGEN, bean.getPerson().getName()); + } + + public void testAutowiredFieldDoesNotResolveCandidateWithDefaultValueAndConflictingValueOnBeanDefinition() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + // qualifier added, and non-default value specified + person1.addQualifier(new AutowireCandidateQualifier(TestQualifierWithDefaultValue.class, "not the default")); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + context.registerBeanDefinition(JUERGEN, person1); + context.registerBeanDefinition(MARK, person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + try { + context.refresh(); + fail("expected BeanCreationException"); + } + catch (BeanCreationException e) { + assertTrue(e.getRootCause() instanceof NoSuchBeanDefinitionException); + assertEquals("autowired", e.getBeanName()); + } + } + + public void testAutowiredFieldResolvesWithDefaultValueAndExplicitDefaultValueOnBeanDefinition() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + // qualifier added, and value matches the default + person1.addQualifier(new AutowireCandidateQualifier(TestQualifierWithDefaultValue.class, "default")); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + context.registerBeanDefinition(JUERGEN, person1); + context.registerBeanDefinition(MARK, person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + context.refresh(); + QualifiedFieldWithDefaultValueTestBean bean = + (QualifiedFieldWithDefaultValueTestBean) context.getBean("autowired"); + assertEquals(JUERGEN, bean.getPerson().getName()); + } + + public void testAutowiredFieldResolvesWithMultipleQualifierValues() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class); + qualifier.setAttribute("number", 456); + person1.addQualifier(qualifier); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + AutowireCandidateQualifier qualifier2 = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class); + qualifier2.setAttribute("number", 123); + person2.addQualifier(qualifier2); + context.registerBeanDefinition(JUERGEN, person1); + context.registerBeanDefinition(MARK, person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + context.refresh(); + QualifiedFieldWithMultipleAttributesTestBean bean = + (QualifiedFieldWithMultipleAttributesTestBean) context.getBean("autowired"); + assertEquals(MARK, bean.getPerson().getName()); + } + + public void testAutowiredFieldDoesNotResolveWithMultipleQualifierValuesAndConflictingDefaultValue() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class); + qualifier.setAttribute("number", 456); + person1.addQualifier(qualifier); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + AutowireCandidateQualifier qualifier2 = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class); + qualifier2.setAttribute("number", 123); + qualifier2.setAttribute("value", "not the default"); + person2.addQualifier(qualifier2); + context.registerBeanDefinition(JUERGEN, person1); + context.registerBeanDefinition(MARK, person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + try { + context.refresh(); + fail("expected BeanCreationException"); + } + catch (BeanCreationException e) { + assertTrue(e.getRootCause() instanceof NoSuchBeanDefinitionException); + assertEquals("autowired", e.getBeanName()); + } + } + + public void testAutowiredFieldResolvesWithMultipleQualifierValuesAndExplicitDefaultValue() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class); + qualifier.setAttribute("number", 456); + person1.addQualifier(qualifier); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + AutowireCandidateQualifier qualifier2 = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class); + qualifier2.setAttribute("number", 123); + qualifier2.setAttribute("value", "default"); + person2.addQualifier(qualifier2); + context.registerBeanDefinition(JUERGEN, person1); + context.registerBeanDefinition(MARK, person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + context.refresh(); + QualifiedFieldWithMultipleAttributesTestBean bean = + (QualifiedFieldWithMultipleAttributesTestBean) context.getBean("autowired"); + assertEquals(MARK, bean.getPerson().getName()); + } + + public void testAutowiredFieldDoesNotResolveWithMultipleQualifierValuesAndMultipleMatchingCandidates() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class); + qualifier.setAttribute("number", 123); + person1.addQualifier(qualifier); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + AutowireCandidateQualifier qualifier2 = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class); + qualifier2.setAttribute("number", 123); + qualifier2.setAttribute("value", "default"); + person2.addQualifier(qualifier2); + context.registerBeanDefinition(JUERGEN, person1); + context.registerBeanDefinition(MARK, person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + try { + context.refresh(); + fail("expected BeanCreationException"); + } + catch (BeanCreationException e) { + assertTrue(e.getRootCause() instanceof NoSuchBeanDefinitionException); + assertEquals("autowired", e.getBeanName()); + } + } + + public void testAutowiredFieldResolvesWithBaseQualifierAndDefaultValue() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue(JUERGEN); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue(MARK); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + person2.addQualifier(new AutowireCandidateQualifier(Qualifier.class)); + context.registerBeanDefinition(JUERGEN, person1); + context.registerBeanDefinition(MARK, person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedFieldWithBaseQualifierDefaultValueTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + context.refresh(); + QualifiedFieldWithBaseQualifierDefaultValueTestBean bean = + (QualifiedFieldWithBaseQualifierDefaultValueTestBean) context.getBean("autowired"); + assertEquals(MARK, bean.getPerson().getName()); + } + + public void testAutowiredFieldResolvesWithBaseQualifierAndNonDefaultValue() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue("the real juergen"); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + person1.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "juergen")); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue("juergen imposter"); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + person2.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "not really juergen")); + context.registerBeanDefinition("juergen1", person1); + context.registerBeanDefinition("juergen2", person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + context.refresh(); + QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean bean = + (QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean) context.getBean("autowired"); + assertEquals("the real juergen", bean.getPerson().getName()); + } + + public void testAutowiredFieldDoesNotResolveWithBaseQualifierAndNonDefaultValueAndMultipleMatchingCandidates() { + GenericApplicationContext context = new GenericApplicationContext(); + ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); + cavs1.addGenericArgumentValue("the real juergen"); + RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); + person1.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "juergen")); + ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); + cavs2.addGenericArgumentValue("juergen imposter"); + RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + person2.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "juergen")); + context.registerBeanDefinition("juergen1", person1); + context.registerBeanDefinition("juergen2", person2); + context.registerBeanDefinition("autowired", + new RootBeanDefinition(QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + try { + context.refresh(); + fail("expected BeanCreationException"); + } + catch (BeanCreationException e) { + assertTrue(e instanceof UnsatisfiedDependencyException); + assertEquals("autowired", e.getBeanName()); + } + } + + + private static class QualifiedFieldTestBean { + + @Autowired + @TestQualifier + private Person person; + + public Person getPerson() { + return this.person; + } + } + + + private static class QualifiedMethodParameterTestBean { + + private Person person; + + @Autowired + public void setPerson(@TestQualifier Person person) { + this.person = person; + } + + public Person getPerson() { + return this.person; + } + } + + + private static class QualifiedConstructorArgumentTestBean { + + private Person person; + + @Autowired + public QualifiedConstructorArgumentTestBean(@TestQualifier Person person) { + this.person = person; + } + + public Person getPerson() { + return this.person; + } + + } + + + public static class QualifiedFieldWithDefaultValueTestBean { + + @Autowired + @TestQualifierWithDefaultValue + private Person person; + + public Person getPerson() { + return this.person; + } + } + + + public static class QualifiedFieldWithMultipleAttributesTestBean { + + @Autowired + @TestQualifierWithMultipleAttributes(number=123) + private Person person; + + public Person getPerson() { + return this.person; + } + } + + + private static class QualifiedFieldWithBaseQualifierDefaultValueTestBean { + + @Autowired + @Qualifier + private Person person; + + public Person getPerson() { + return this.person; + } + } + + + public static class QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean { + + private Person person; + + @Autowired + public QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean( + @Qualifier("juergen") Person person) { + this.person = person; + } + + public Person getPerson() { + return this.person; + } + } + + + private static class Person { + + private String name; + + public Person(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + } + + + @TestQualifier + private static class QualifiedPerson extends Person { + + public QualifiedPerson(String name) { + super(name); + } + } + + + @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @Qualifier + public static @interface TestQualifier { + } + + + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.RUNTIME) + @Qualifier + public static @interface TestQualifierWithDefaultValue { + + String value() default "default"; + + } + + + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.RUNTIME) + @Qualifier + public static @interface TestQualifierWithMultipleAttributes { + + String value() default "default"; + + int number(); + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/genericBeanTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/genericBeanTests.xml new file mode 100644 index 00000000000..a2c2585b783 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/genericBeanTests.xml @@ -0,0 +1,70 @@ + + + + + + + + + + value1 + value2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 20 + 30 + + + + + + + + + 20 + 30 + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/QualifierAnnotationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/QualifierAnnotationTests.java new file mode 100644 index 00000000000..a25e932f3de --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/QualifierAnnotationTests.java @@ -0,0 +1,287 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver; +import org.springframework.beans.factory.support.BeanDefinitionReader; +import org.springframework.context.support.StaticApplicationContext; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +public class QualifierAnnotationTests extends TestCase { + + private static final String CONFIG_LOCATION = + "classpath:org/springframework/beans/factory/xml/qualifierAnnotationTests.xml"; + + + public void testNonQualifiedFieldFails() { + StaticApplicationContext context = new StaticApplicationContext(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(CONFIG_LOCATION); + context.registerSingleton("testBean", NonQualifiedTestBean.class); + try { + context.refresh(); + fail("Should have thrown a BeanCreationException"); + } + catch (BeanCreationException e) { + assertTrue(e.getMessage().contains("found 6")); + } + } + + public void testQualifiedByValue() { + StaticApplicationContext context = new StaticApplicationContext(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(CONFIG_LOCATION); + context.registerSingleton("testBean", QualifiedByValueTestBean.class); + context.refresh(); + QualifiedByValueTestBean testBean = (QualifiedByValueTestBean) context.getBean("testBean"); + Person person = testBean.getLarry(); + assertEquals("Larry", person.getName()); + } + + public void testQualifiedByBeanName() { + StaticApplicationContext context = new StaticApplicationContext(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(CONFIG_LOCATION); + context.registerSingleton("testBean", QualifiedByBeanNameTestBean.class); + context.refresh(); + QualifiedByBeanNameTestBean testBean = (QualifiedByBeanNameTestBean) context.getBean("testBean"); + Person person = testBean.getLarry(); + assertEquals("LarryBean", person.getName()); + } + + public void testQualifiedByAlias() { + StaticApplicationContext context = new StaticApplicationContext(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(CONFIG_LOCATION); + context.registerSingleton("testBean", QualifiedByAliasTestBean.class); + context.refresh(); + QualifiedByAliasTestBean testBean = (QualifiedByAliasTestBean) context.getBean("testBean"); + Person person = testBean.getStooge(); + assertEquals("LarryBean", person.getName()); + } + + public void testQualifiedByAnnotation() { + StaticApplicationContext context = new StaticApplicationContext(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(CONFIG_LOCATION); + context.registerSingleton("testBean", QualifiedByAnnotationTestBean.class); + context.refresh(); + QualifiedByAnnotationTestBean testBean = (QualifiedByAnnotationTestBean) context.getBean("testBean"); + Person person = testBean.getLarry(); + assertEquals("LarrySpecial", person.getName()); + } + + public void testQualifiedByCustomValue() { + StaticApplicationContext context = new StaticApplicationContext(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(CONFIG_LOCATION); + context.registerSingleton("testBean", QualifiedByCustomValueTestBean.class); + context.refresh(); + QualifiedByCustomValueTestBean testBean = (QualifiedByCustomValueTestBean) context.getBean("testBean"); + Person person = testBean.getCurly(); + assertEquals("Curly", person.getName()); + } + + public void testQualifiedByAnnotationValue() { + StaticApplicationContext context = new StaticApplicationContext(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(CONFIG_LOCATION); + context.registerSingleton("testBean", QualifiedByAnnotationValueTestBean.class); + context.refresh(); + QualifiedByAnnotationValueTestBean testBean = (QualifiedByAnnotationValueTestBean) context.getBean("testBean"); + Person person = testBean.getLarry(); + assertEquals("LarrySpecial", person.getName()); + } + + public void testQualifiedByAttributesFailsWithoutCustomQualifierRegistered() { + StaticApplicationContext context = new StaticApplicationContext(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(CONFIG_LOCATION); + context.registerSingleton("testBean", QualifiedByAttributesTestBean.class); + try { + context.refresh(); + fail("should have thrown a BeanCreationException"); + } + catch (BeanCreationException e) { + assertTrue(e.getMessage().contains("found 6")); + } + } + + public void testQualifiedByAttributesWithCustomQualifierRegistered() { + StaticApplicationContext context = new StaticApplicationContext(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(CONFIG_LOCATION); + QualifierAnnotationAutowireCandidateResolver resolver = (QualifierAnnotationAutowireCandidateResolver) + context.getDefaultListableBeanFactory().getAutowireCandidateResolver(); + resolver.addQualifierType(MultipleAttributeQualifier.class); + context.registerSingleton("testBean", QualifiedByAttributesTestBean.class); + context.refresh(); + QualifiedByAttributesTestBean testBean = (QualifiedByAttributesTestBean) context.getBean("testBean"); + Person moeSenior = testBean.getMoeSenior(); + Person moeJunior = testBean.getMoeJunior(); + assertEquals("Moe Sr.", moeSenior.getName()); + assertEquals("Moe Jr.", moeJunior.getName()); + } + + + private static class NonQualifiedTestBean { + + @Autowired + private Person anonymous; + + public Person getAnonymous() { + return anonymous; + } + } + + + private static class QualifiedByValueTestBean { + + @Autowired @Qualifier("larry") + private Person larry; + + public Person getLarry() { + return larry; + } + } + + + private static class QualifiedByBeanNameTestBean { + + @Autowired @Qualifier("larryBean") + private Person larry; + + public Person getLarry() { + return larry; + } + } + + + private static class QualifiedByAliasTestBean { + + @Autowired @Qualifier("stooge") + private Person stooge; + + public Person getStooge() { + return stooge; + } + } + + + private static class QualifiedByAnnotationTestBean { + + @Autowired @Qualifier("special") + private Person larry; + + public Person getLarry() { + return larry; + } + } + + + private static class QualifiedByCustomValueTestBean { + + @Autowired @SimpleValueQualifier("curly") + private Person curly; + + public Person getCurly() { + return curly; + } + } + + + private static class QualifiedByAnnotationValueTestBean { + + @Autowired @SimpleValueQualifier("special") + private Person larry; + + public Person getLarry() { + return larry; + } + } + + + private static class QualifiedByAttributesTestBean { + + @Autowired @MultipleAttributeQualifier(name="moe", age=42) + private Person moeSenior; + + @Autowired @MultipleAttributeQualifier(name="moe", age=15) + private Person moeJunior; + + public Person getMoeSenior() { + return moeSenior; + } + + public Person getMoeJunior() { + return moeJunior; + } + } + + + private static class Person { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + + @Qualifier("special") + @SimpleValueQualifier("special") + private static class SpecialPerson extends Person { + } + + + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @Qualifier + public @interface SimpleValueQualifier { + + String value() default ""; + } + + + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.RUNTIME) + public @interface MultipleAttributeQualifier { + + String name(); + + int age(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/qualifierAnnotationTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/qualifierAnnotationTests.xml new file mode 100644 index 00000000000..e39acbf5ef6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/qualifierAnnotationTests.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AnnotationBeanNameGeneratorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AnnotationBeanNameGeneratorTests.java new file mode 100644 index 00000000000..17e99fc31e9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AnnotationBeanNameGeneratorTests.java @@ -0,0 +1,115 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; +import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +/** + * @author Rick Evans + * @author Juergen Hoeller + * @author Mark Fisher + */ +public class AnnotationBeanNameGeneratorTests extends TestCase { + + private AnnotationBeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator(); + + + public void testGenerateBeanNameWithNamedComponent() { + MockControl control = MockControl.createControl(BeanDefinitionRegistry.class); + BeanDefinitionRegistry registry = (BeanDefinitionRegistry) control.getMock(); + control.replay(); + + AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(ComponentWithName.class); + String beanName = this.beanNameGenerator.generateBeanName(bd, registry); + assertNotNull("The generated beanName must *never* be null.", beanName); + assertTrue("The generated beanName must *never* be blank.", StringUtils.hasText(beanName)); + assertEquals("walden", beanName); + + control.verify(); + } + + public void testGenerateBeanNameWithDefaultNamedComponent() { + MockControl control = MockControl.createControl(BeanDefinitionRegistry.class); + BeanDefinitionRegistry registry = (BeanDefinitionRegistry) control.getMock(); + control.replay(); + + AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(DefaultNamedComponent.class); + String beanName = this.beanNameGenerator.generateBeanName(bd, registry); + assertNotNull("The generated beanName must *never* be null.", beanName); + assertTrue("The generated beanName must *never* be blank.", StringUtils.hasText(beanName)); + assertEquals("thoreau", beanName); + + control.verify(); + } + + public void testGenerateBeanNameWithNamedComponentWhereTheNameIsBlank() { + MockControl control = MockControl.createControl(BeanDefinitionRegistry.class); + BeanDefinitionRegistry registry = (BeanDefinitionRegistry) control.getMock(); + control.replay(); + + AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(ComponentWithBlankName.class); + String beanName = this.beanNameGenerator.generateBeanName(bd, registry); + assertNotNull("The generated beanName must *never* be null.", beanName); + assertTrue("The generated beanName must *never* be blank.", StringUtils.hasText(beanName)); + + String expectedGeneratedBeanName = this.beanNameGenerator.buildDefaultBeanName(bd); + + assertEquals(expectedGeneratedBeanName, beanName); + + control.verify(); + } + + public void testGenerateBeanNameWithAnonymousComponentYieldsGeneratedBeanName() { + MockControl control = MockControl.createControl(BeanDefinitionRegistry.class); + BeanDefinitionRegistry registry = (BeanDefinitionRegistry) control.getMock(); + control.replay(); + + AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(AnonymousComponent.class); + String beanName = this.beanNameGenerator.generateBeanName(bd, registry); + assertNotNull("The generated beanName must *never* be null.", beanName); + assertTrue("The generated beanName must *never* be blank.", StringUtils.hasText(beanName)); + + String expectedGeneratedBeanName = this.beanNameGenerator.buildDefaultBeanName(bd); + + assertEquals(expectedGeneratedBeanName, beanName); + + control.verify(); + } + + + @Component("walden") + private static class ComponentWithName { + } + + + @Component(" ") + private static class ComponentWithBlankName { + } + + + @Component + private static class AnonymousComponent { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AnnotationProcessorPerformanceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AnnotationProcessorPerformanceTests.java new file mode 100644 index 00000000000..3bed5606020 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AnnotationProcessorPerformanceTests.java @@ -0,0 +1,163 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import javax.annotation.Resource; + +import junit.framework.TestCase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Required; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.util.StopWatch; + +/** + * @author Juergen Hoeller + * @since 2.5 + */ +public class AnnotationProcessorPerformanceTests extends TestCase { + + private static final Log factoryLog = LogFactory.getLog(DefaultListableBeanFactory.class); + + public void testPrototypeCreationWithResourcePropertiesIsFastEnough() { + if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + GenericApplicationContext ctx = new GenericApplicationContext(); + AnnotationConfigUtils.registerAnnotationConfigProcessors(ctx); + ctx.refresh(); + + RootBeanDefinition rbd = new RootBeanDefinition(ResourceAnnotatedTestBean.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + ctx.registerBeanDefinition("test", rbd); + ctx.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); + TestBean spouse = (TestBean) ctx.getBean("spouse"); + StopWatch sw = new StopWatch(); + sw.start("prototype"); + for (int i = 0; i < 100000; i++) { + TestBean tb = (TestBean) ctx.getBean("test"); + assertSame(spouse, tb.getSpouse()); + } + sw.stop(); + //System.out.println(sw.getTotalTimeMillis()); + assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 4000); + } + + public void testPrototypeCreationWithOverriddenResourcePropertiesIsFastEnough() { + if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + GenericApplicationContext ctx = new GenericApplicationContext(); + AnnotationConfigUtils.registerAnnotationConfigProcessors(ctx); + ctx.refresh(); + + RootBeanDefinition rbd = new RootBeanDefinition(ResourceAnnotatedTestBean.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.getPropertyValues().addPropertyValue("spouse", new RuntimeBeanReference("spouse")); + ctx.registerBeanDefinition("test", rbd); + ctx.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); + TestBean spouse = (TestBean) ctx.getBean("spouse"); + StopWatch sw = new StopWatch(); + sw.start("prototype"); + for (int i = 0; i < 100000; i++) { + TestBean tb = (TestBean) ctx.getBean("test"); + assertSame(spouse, tb.getSpouse()); + } + sw.stop(); + //System.out.println(sw.getTotalTimeMillis()); + assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 4000); + } + + public void testPrototypeCreationWithAutowiredPropertiesIsFastEnough() { + if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + GenericApplicationContext ctx = new GenericApplicationContext(); + AnnotationConfigUtils.registerAnnotationConfigProcessors(ctx); + ctx.refresh(); + + RootBeanDefinition rbd = new RootBeanDefinition(AutowiredAnnotatedTestBean.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + ctx.registerBeanDefinition("test", rbd); + ctx.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); + TestBean spouse = (TestBean) ctx.getBean("spouse"); + StopWatch sw = new StopWatch(); + sw.start("prototype"); + for (int i = 0; i < 100000; i++) { + TestBean tb = (TestBean) ctx.getBean("test"); + assertSame(spouse, tb.getSpouse()); + } + sw.stop(); + //System.out.println(sw.getTotalTimeMillis()); + assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 4000); + } + + public void testPrototypeCreationWithOverriddenAutowiredPropertiesIsFastEnough() { + if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + GenericApplicationContext ctx = new GenericApplicationContext(); + AnnotationConfigUtils.registerAnnotationConfigProcessors(ctx); + ctx.refresh(); + + RootBeanDefinition rbd = new RootBeanDefinition(AutowiredAnnotatedTestBean.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.getPropertyValues().addPropertyValue("spouse", new RuntimeBeanReference("spouse")); + ctx.registerBeanDefinition("test", rbd); + ctx.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); + TestBean spouse = (TestBean) ctx.getBean("spouse"); + StopWatch sw = new StopWatch(); + sw.start("prototype"); + for (int i = 0; i < 100000; i++) { + TestBean tb = (TestBean) ctx.getBean("test"); + assertSame(spouse, tb.getSpouse()); + } + sw.stop(); + //System.out.println(sw.getTotalTimeMillis()); + assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 4000); + } + + + private static class ResourceAnnotatedTestBean extends TestBean { + + @Resource @Required + public void setSpouse(ITestBean spouse) { + super.setSpouse(spouse); + } + } + + + private static class AutowiredAnnotatedTestBean extends TestBean { + + @Autowired @Required + public void setSpouse(ITestBean spouse) { + super.setSpouse(spouse); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AnnotationScopeMetadataResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AnnotationScopeMetadataResolverTests.java new file mode 100644 index 00000000000..9b2334de91a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AnnotationScopeMetadataResolverTests.java @@ -0,0 +1,69 @@ +package org.springframework.context.annotation; + +import junit.framework.TestCase; +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; +import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.test.AssertThrows; + +/** + * Unit tests for the {@link AnnotationScopeMetadataResolver} class. + * + * @author Rick Evans + */ +public final class AnnotationScopeMetadataResolverTests extends TestCase { + + private AnnotationScopeMetadataResolver scopeMetadataResolver; + + + @Override + protected void setUp() throws Exception { + this.scopeMetadataResolver = new AnnotationScopeMetadataResolver(); + } + + + public void testThatResolveScopeMetadataDoesNotApplyScopedProxyModeToASingleton() { + AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(AnnotatedWithSingletonScope.class); + ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(bd); + assertNotNull("resolveScopeMetadata(..) must *never* return null.", scopeMetadata); + assertEquals(BeanDefinition.SCOPE_SINGLETON, scopeMetadata.getScopeName()); + assertEquals(ScopedProxyMode.NO, scopeMetadata.getScopedProxyMode()); + } + + + public void testThatResolveScopeMetadataDoesApplyScopedProxyModeToAPrototype() { + this.scopeMetadataResolver = new AnnotationScopeMetadataResolver(ScopedProxyMode.INTERFACES); + AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(AnnotatedWithPrototypeScope.class); + ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(bd); + assertNotNull("resolveScopeMetadata(..) must *never* return null.", scopeMetadata); + assertEquals(BeanDefinition.SCOPE_PROTOTYPE, scopeMetadata.getScopeName()); + assertEquals(ScopedProxyMode.INTERFACES, scopeMetadata.getScopedProxyMode()); + } + + public void testCtorWithNullScopedProxyMode() { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new AnnotationScopeMetadataResolver(null); + } + }.runTest(); + } + + public void testSetScopeAnnotationTypeWithNullType() { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + scopeMetadataResolver.setScopeAnnotationType(null); + } + }.runTest(); + } + + + @Scope("singleton") + private static final class AnnotatedWithSingletonScope { + } + + + @Scope("prototype") + private static final class AnnotatedWithPrototypeScope { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AutowiredQualifierFooService.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AutowiredQualifierFooService.java new file mode 100644 index 00000000000..8884a075590 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/AutowiredQualifierFooService.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +/** + * @author Mark Fisher + */ +public class AutowiredQualifierFooService implements FooService { + + @Autowired + @Qualifier("testing") + private FooDao fooDao; + + private boolean initCalled = false; + + @PostConstruct + private void init() { + if (this.initCalled) { + throw new IllegalStateException("Init already called"); + } + this.initCalled = true; + } + + public String foo(int id) { + return this.fooDao.findFoo(id); + } + + public boolean isInitCalled() { + return this.initCalled; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerScopeTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerScopeTests.java new file mode 100644 index 00000000000..ab5ffcec649 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerScopeTests.java @@ -0,0 +1,331 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import junit.framework.TestCase; + +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.context.ApplicationContext; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.util.ClassUtils; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.context.support.GenericWebApplicationContext; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +public class ClassPathBeanDefinitionScannerScopeTests extends TestCase { + + private static final String DEFAULT_NAME = "default"; + + private static final String MODIFIED_NAME = "modified"; + + private ServletRequestAttributes oldRequestAttributes; + + private ServletRequestAttributes newRequestAttributes; + + private ServletRequestAttributes oldRequestAttributesWithSession; + + private ServletRequestAttributes newRequestAttributesWithSession; + + + public void setUp() { + this.oldRequestAttributes = new ServletRequestAttributes(new MockHttpServletRequest()); + this.newRequestAttributes = new ServletRequestAttributes(new MockHttpServletRequest()); + + MockHttpServletRequest oldRequestWithSession = new MockHttpServletRequest(); + oldRequestWithSession.setSession(new MockHttpSession()); + this.oldRequestAttributesWithSession = new ServletRequestAttributes(oldRequestWithSession); + + MockHttpServletRequest newRequestWithSession = new MockHttpServletRequest(); + newRequestWithSession.setSession(new MockHttpSession()); + this.newRequestAttributesWithSession = new ServletRequestAttributes(newRequestWithSession); + } + + protected void tearDown() throws Exception { + RequestContextHolder.setRequestAttributes(null); + } + + + public void testSingletonScopeWithNoProxy() { + RequestContextHolder.setRequestAttributes(oldRequestAttributes); + ApplicationContext context = createContext(ScopedProxyMode.NO); + ScopedTestBean bean = (ScopedTestBean) context.getBean("singleton"); + + // should not be a proxy + assertFalse(AopUtils.isAopProxy(bean)); + + assertEquals(DEFAULT_NAME, bean.getName()); + bean.setName(MODIFIED_NAME); + + RequestContextHolder.setRequestAttributes(newRequestAttributes); + // not a proxy so this should not have changed + assertEquals(MODIFIED_NAME, bean.getName()); + + // singleton bean, so name should be modified even after lookup + ScopedTestBean bean2 = (ScopedTestBean) context.getBean("singleton"); + assertEquals(MODIFIED_NAME, bean2.getName()); + } + + public void testSingletonScopeIgnoresProxyInterfaces() { + RequestContextHolder.setRequestAttributes(oldRequestAttributes); + ApplicationContext context = createContext(ScopedProxyMode.INTERFACES); + ScopedTestBean bean = (ScopedTestBean) context.getBean("singleton"); + + // should not be a proxy + assertFalse(AopUtils.isAopProxy(bean)); + + assertEquals(DEFAULT_NAME, bean.getName()); + bean.setName(MODIFIED_NAME); + + RequestContextHolder.setRequestAttributes(newRequestAttributes); + // not a proxy so this should not have changed + assertEquals(MODIFIED_NAME, bean.getName()); + + // singleton bean, so name should be modified even after lookup + ScopedTestBean bean2 = (ScopedTestBean) context.getBean("singleton"); + assertEquals(MODIFIED_NAME, bean2.getName()); + } + + public void testSingletonScopeIgnoresProxyTargetClass() { + RequestContextHolder.setRequestAttributes(oldRequestAttributes); + ApplicationContext context = createContext(ScopedProxyMode.TARGET_CLASS); + ScopedTestBean bean = (ScopedTestBean) context.getBean("singleton"); + + // should not be a proxy + assertFalse(AopUtils.isAopProxy(bean)); + + assertEquals(DEFAULT_NAME, bean.getName()); + bean.setName(MODIFIED_NAME); + + RequestContextHolder.setRequestAttributes(newRequestAttributes); + // not a proxy so this should not have changed + assertEquals(MODIFIED_NAME, bean.getName()); + + // singleton bean, so name should be modified even after lookup + ScopedTestBean bean2 = (ScopedTestBean) context.getBean("singleton"); + assertEquals(MODIFIED_NAME, bean2.getName()); + } + + public void testRequestScopeWithNoProxy() { + RequestContextHolder.setRequestAttributes(oldRequestAttributes); + ApplicationContext context = createContext(ScopedProxyMode.NO); + ScopedTestBean bean = (ScopedTestBean) context.getBean("request"); + + // should not be a proxy + assertFalse(AopUtils.isAopProxy(bean)); + + assertEquals(DEFAULT_NAME, bean.getName()); + bean.setName(MODIFIED_NAME); + + RequestContextHolder.setRequestAttributes(newRequestAttributes); + // not a proxy so this should not have changed + assertEquals(MODIFIED_NAME, bean.getName()); + + // but a newly retrieved bean should have the default name + ScopedTestBean bean2 = (ScopedTestBean) context.getBean("request"); + assertEquals(DEFAULT_NAME, bean2.getName()); + } + + public void testRequestScopeWithProxiedInterfaces() { + RequestContextHolder.setRequestAttributes(oldRequestAttributes); + ApplicationContext context = createContext(ScopedProxyMode.INTERFACES); + IScopedTestBean bean = (IScopedTestBean) context.getBean("request"); + + // should be dynamic proxy, implementing both interfaces + assertTrue(AopUtils.isJdkDynamicProxy(bean)); + assertTrue(bean instanceof AnotherScopeTestInterface); + + assertEquals(DEFAULT_NAME, bean.getName()); + bean.setName(MODIFIED_NAME); + + RequestContextHolder.setRequestAttributes(newRequestAttributes); + // this is a proxy so it should be reset to default + assertEquals(DEFAULT_NAME, bean.getName()); + + RequestContextHolder.setRequestAttributes(oldRequestAttributes); + assertEquals(MODIFIED_NAME, bean.getName()); + } + + public void testRequestScopeWithProxiedTargetClass() { + RequestContextHolder.setRequestAttributes(oldRequestAttributes); + ApplicationContext context = createContext(ScopedProxyMode.TARGET_CLASS); + IScopedTestBean bean = (IScopedTestBean) context.getBean("request"); + + // should be a class-based proxy + assertTrue(AopUtils.isCglibProxy(bean)); + assertTrue(bean instanceof RequestScopedTestBean); + + assertEquals(DEFAULT_NAME, bean.getName()); + bean.setName(MODIFIED_NAME); + + RequestContextHolder.setRequestAttributes(newRequestAttributes); + // this is a proxy so it should be reset to default + assertEquals(DEFAULT_NAME, bean.getName()); + + RequestContextHolder.setRequestAttributes(oldRequestAttributes); + assertEquals(MODIFIED_NAME, bean.getName()); + } + + public void testSessionScopeWithNoProxy() { + RequestContextHolder.setRequestAttributes(oldRequestAttributesWithSession); + ApplicationContext context = createContext(ScopedProxyMode.NO); + ScopedTestBean bean = (ScopedTestBean) context.getBean("session"); + + // should not be a proxy + assertFalse(AopUtils.isAopProxy(bean)); + + assertEquals(DEFAULT_NAME, bean.getName()); + bean.setName(MODIFIED_NAME); + + RequestContextHolder.setRequestAttributes(newRequestAttributesWithSession); + // not a proxy so this should not have changed + assertEquals(MODIFIED_NAME, bean.getName()); + + // but a newly retrieved bean should have the default name + ScopedTestBean bean2 = (ScopedTestBean) context.getBean("session"); + assertEquals(DEFAULT_NAME, bean2.getName()); + } + + public void testSessionScopeWithProxiedInterfaces() { + RequestContextHolder.setRequestAttributes(oldRequestAttributesWithSession); + ApplicationContext context = createContext(ScopedProxyMode.INTERFACES); + IScopedTestBean bean = (IScopedTestBean) context.getBean("session"); + + // should be dynamic proxy, implementing both interfaces + assertTrue(AopUtils.isJdkDynamicProxy(bean)); + assertTrue(bean instanceof AnotherScopeTestInterface); + + assertEquals(DEFAULT_NAME, bean.getName()); + bean.setName(MODIFIED_NAME); + + RequestContextHolder.setRequestAttributes(newRequestAttributesWithSession); + // this is a proxy so it should be reset to default + assertEquals(DEFAULT_NAME, bean.getName()); + bean.setName(MODIFIED_NAME); + + IScopedTestBean bean2 = (IScopedTestBean) context.getBean("session"); + assertEquals(MODIFIED_NAME, bean2.getName()); + bean2.setName(DEFAULT_NAME); + assertEquals(DEFAULT_NAME, bean.getName()); + + RequestContextHolder.setRequestAttributes(oldRequestAttributesWithSession); + assertEquals(MODIFIED_NAME, bean.getName()); + } + + public void testSessionScopeWithProxiedTargetClass() { + RequestContextHolder.setRequestAttributes(oldRequestAttributesWithSession); + ApplicationContext context = createContext(ScopedProxyMode.TARGET_CLASS); + IScopedTestBean bean = (IScopedTestBean) context.getBean("session"); + + // should be a class-based proxy + assertTrue(AopUtils.isCglibProxy(bean)); + assertTrue(bean instanceof ScopedTestBean); + assertTrue(bean instanceof SessionScopedTestBean); + + assertEquals(DEFAULT_NAME, bean.getName()); + bean.setName(MODIFIED_NAME); + + RequestContextHolder.setRequestAttributes(newRequestAttributesWithSession); + // this is a proxy so it should be reset to default + assertEquals(DEFAULT_NAME, bean.getName()); + bean.setName(MODIFIED_NAME); + + IScopedTestBean bean2 = (IScopedTestBean) context.getBean("session"); + assertEquals(MODIFIED_NAME, bean2.getName()); + bean2.setName(DEFAULT_NAME); + assertEquals(DEFAULT_NAME, bean.getName()); + + RequestContextHolder.setRequestAttributes(oldRequestAttributesWithSession); + assertEquals(MODIFIED_NAME, bean.getName()); + } + + + private ApplicationContext createContext(ScopedProxyMode scopedProxyMode) { + GenericWebApplicationContext context = new GenericWebApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, false); + scanner.setIncludeAnnotationConfig(false); + scanner.addIncludeFilter(new AnnotationTypeFilter(ScopeTestComponent.class)); + scanner.setBeanNameGenerator(new BeanNameGenerator() { + public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { + String beanClassName = ClassUtils.getShortName(definition.getBeanClassName()); + int begin = beanClassName.lastIndexOf('.') + 1; + int end = beanClassName.lastIndexOf("ScopedTestBean"); + return beanClassName.substring(begin, end).toLowerCase(); + } + }); + scanner.setScopedProxyMode(scopedProxyMode); + + // Scan twice in order to find errors in the bean definition compatibility check. + scanner.scan(getClass().getPackage().getName()); + scanner.scan(getClass().getPackage().getName()); + + context.refresh(); + return context; + } + + + public static @interface ScopeTestComponent { + } + + + public static interface IScopedTestBean { + + String getName(); + + void setName(String name); + } + + + public static abstract class ScopedTestBean implements IScopedTestBean { + + private String name = DEFAULT_NAME; + + public String getName() { return this.name; } + + public void setName(String name) { this.name = name; } + } + + + @ScopeTestComponent + public static class SingletonScopedTestBean extends ScopedTestBean { + } + + + public static interface AnotherScopeTestInterface { + } + + + @Scope("request") + @ScopeTestComponent + public static class RequestScopedTestBean extends ScopedTestBean implements AnotherScopeTestInterface { + } + + + @Scope("session") + @ScopeTestComponent + public static class SessionScopedTestBean extends ScopedTestBean implements AnotherScopeTestInterface { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java new file mode 100644 index 00000000000..fcf2916a140 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java @@ -0,0 +1,411 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import junit.framework.TestCase; +import org.aspectj.lang.annotation.Aspect; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.support.StaticListableBeanFactory; +import org.springframework.context.MessageSource; +import org.springframework.context.annotation2.NamedStubDao2; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.core.type.filter.AssignableTypeFilter; +import org.springframework.stereotype.Component; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +public class ClassPathBeanDefinitionScannerTests extends TestCase { + + private static final String BASE_PACKAGE = + ClassPathBeanDefinitionScannerTests.class.getPackage().getName(); + + + public void testSimpleScanWithDefaultFiltersAndPostProcessors() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(13, beanCount); + assertTrue(context.containsBean("serviceInvocationCounter")); + assertTrue(context.containsBean("fooServiceImpl")); + assertTrue(context.containsBean("stubFooDao")); + assertTrue(context.containsBean("myNamedComponent")); + assertTrue(context.containsBean("myNamedDao")); + assertTrue(context.containsBean("thoreau")); + assertTrue(context.containsBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + } + + public void testDoubleScan() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(13, beanCount); + scanner.scan(BASE_PACKAGE); + assertTrue(context.containsBean("serviceInvocationCounter")); + assertTrue(context.containsBean("fooServiceImpl")); + assertTrue(context.containsBean("stubFooDao")); + assertTrue(context.containsBean("myNamedComponent")); + assertTrue(context.containsBean("myNamedDao")); + assertTrue(context.containsBean("thoreau")); + } + + public void testSimpleScanWithDefaultFiltersAndNoPostProcessors() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + scanner.setIncludeAnnotationConfig(false); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(9, beanCount); + assertTrue(context.containsBean("serviceInvocationCounter")); + assertTrue(context.containsBean("fooServiceImpl")); + assertTrue(context.containsBean("stubFooDao")); + assertTrue(context.containsBean("myNamedComponent")); + assertTrue(context.containsBean("myNamedDao")); + } + + public void testSimpleScanWithDefaultFiltersAndOverridingBean() { + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBeanDefinition("stubFooDao", new RootBeanDefinition(TestBean.class)); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + scanner.setIncludeAnnotationConfig(false); + // should not fail! + scanner.scan(BASE_PACKAGE); + } + + public void testSimpleScanWithDefaultFiltersAndDefaultBeanNameClash() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + scanner.setIncludeAnnotationConfig(false); + try { + scanner.scan("org.springframework.context.annotation3"); + scanner.scan(BASE_PACKAGE); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + assertTrue(ex.getMessage().indexOf("stubFooDao") != -1); + assertTrue(ex.getMessage().indexOf(StubFooDao.class.getName()) != -1); + } + } + + public void testSimpleScanWithDefaultFiltersAndOverriddenEqualNamedBean() { + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBeanDefinition("myNamedDao", new RootBeanDefinition(NamedStubDao.class)); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + scanner.setIncludeAnnotationConfig(false); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(8, beanCount); + assertEquals(9, context.getBeanDefinitionCount()); + assertTrue(context.containsBean("serviceInvocationCounter")); + assertTrue(context.containsBean("fooServiceImpl")); + assertTrue(context.containsBean("stubFooDao")); + assertTrue(context.containsBean("myNamedComponent")); + assertTrue(context.containsBean("myNamedDao")); + } + + public void testSimpleScanWithDefaultFiltersAndOverriddenCompatibleNamedBean() { + GenericApplicationContext context = new GenericApplicationContext(); + RootBeanDefinition bd = new RootBeanDefinition(NamedStubDao.class); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + context.registerBeanDefinition("myNamedDao", bd); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + scanner.setIncludeAnnotationConfig(false); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(8, beanCount); + assertEquals(9, context.getBeanDefinitionCount()); + assertTrue(context.containsBean("serviceInvocationCounter")); + assertTrue(context.containsBean("fooServiceImpl")); + assertTrue(context.containsBean("stubFooDao")); + assertTrue(context.containsBean("myNamedComponent")); + assertTrue(context.containsBean("myNamedDao")); + } + + public void testSimpleScanWithDefaultFiltersAndSameBeanTwice() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + scanner.setIncludeAnnotationConfig(false); + // should not fail! + scanner.scan(BASE_PACKAGE); + scanner.scan(BASE_PACKAGE); + } + + public void testSimpleScanWithDefaultFiltersAndSpecifiedBeanNameClash() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + scanner.setIncludeAnnotationConfig(false); + try { + scanner.scan("org.springframework.context.annotation2"); + scanner.scan(BASE_PACKAGE); + fail("Must have thrown IllegalStateException"); + } + catch (IllegalStateException expected) { + assertTrue(expected.getMessage().contains("myNamedDao")); + assertTrue(expected.getMessage().contains(NamedStubDao.class.getName())); + assertTrue(expected.getMessage().contains(NamedStubDao2.class.getName())); + } + } + + public void testCustomIncludeFilterWithoutDefaultsButIncludingPostProcessors() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, false); + scanner.addIncludeFilter(new AnnotationTypeFilter(CustomComponent.class)); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(5, beanCount); + assertTrue(context.containsBean("messageBean")); + assertTrue(context.containsBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + } + + public void testCustomIncludeFilterWithoutDefaultsAndNoPostProcessors() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, false); + scanner.addIncludeFilter(new AnnotationTypeFilter(CustomComponent.class)); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(5, beanCount); + assertTrue(context.containsBean("messageBean")); + assertFalse(context.containsBean("serviceInvocationCounter")); + assertFalse(context.containsBean("fooServiceImpl")); + assertFalse(context.containsBean("stubFooDao")); + assertFalse(context.containsBean("myNamedComponent")); + assertFalse(context.containsBean("myNamedDao")); + assertTrue(context.containsBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + } + + public void testCustomIncludeFilterAndDefaults() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, true); + scanner.addIncludeFilter(new AnnotationTypeFilter(CustomComponent.class)); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(14, beanCount); + assertTrue(context.containsBean("messageBean")); + assertTrue(context.containsBean("serviceInvocationCounter")); + assertTrue(context.containsBean("fooServiceImpl")); + assertTrue(context.containsBean("stubFooDao")); + assertTrue(context.containsBean("myNamedComponent")); + assertTrue(context.containsBean("myNamedDao")); + assertTrue(context.containsBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + } + + public void testCustomAnnotationExcludeFilterAndDefaults() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, true); + scanner.addExcludeFilter(new AnnotationTypeFilter(Aspect.class)); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(12, beanCount); + assertFalse(context.containsBean("serviceInvocationCounter")); + assertTrue(context.containsBean("fooServiceImpl")); + assertTrue(context.containsBean("stubFooDao")); + assertTrue(context.containsBean("myNamedComponent")); + assertTrue(context.containsBean("myNamedDao")); + assertTrue(context.containsBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + } + + public void testCustomAssignableTypeExcludeFilterAndDefaults() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, true); + scanner.addExcludeFilter(new AssignableTypeFilter(FooService.class)); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(12, beanCount); + assertFalse(context.containsBean("fooServiceImpl")); + assertTrue(context.containsBean("serviceInvocationCounter")); + assertTrue(context.containsBean("stubFooDao")); + assertTrue(context.containsBean("myNamedComponent")); + assertTrue(context.containsBean("myNamedDao")); + assertTrue(context.containsBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + } + + public void testCustomAssignableTypeExcludeFilterAndDefaultsWithoutPostProcessors() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, true); + scanner.setIncludeAnnotationConfig(false); + scanner.addExcludeFilter(new AssignableTypeFilter(FooService.class)); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(8, beanCount); + assertFalse(context.containsBean("fooServiceImpl")); + assertTrue(context.containsBean("serviceInvocationCounter")); + assertTrue(context.containsBean("stubFooDao")); + assertTrue(context.containsBean("myNamedComponent")); + assertTrue(context.containsBean("myNamedDao")); + assertFalse(context.containsBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertFalse(context.containsBean(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertFalse(context.containsBean(AnnotationConfigUtils.REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + } + + public void testMultipleCustomExcludeFiltersAndDefaults() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, true); + scanner.addExcludeFilter(new AssignableTypeFilter(FooService.class)); + scanner.addExcludeFilter(new AnnotationTypeFilter(Aspect.class)); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(11, beanCount); + assertFalse(context.containsBean("fooServiceImpl")); + assertFalse(context.containsBean("serviceInvocationCounter")); + assertTrue(context.containsBean("stubFooDao")); + assertTrue(context.containsBean("myNamedComponent")); + assertTrue(context.containsBean("myNamedDao")); + assertTrue(context.containsBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + } + + public void testCustomBeanNameGenerator() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + scanner.setBeanNameGenerator(new TestBeanNameGenerator()); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(13, beanCount); + assertFalse(context.containsBean("fooServiceImpl")); + assertTrue(context.containsBean("fooService")); + assertTrue(context.containsBean("serviceInvocationCounter")); + assertTrue(context.containsBean("stubFooDao")); + assertTrue(context.containsBean("myNamedComponent")); + assertTrue(context.containsBean("myNamedDao")); + assertTrue(context.containsBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); + assertTrue(context.containsBean(AnnotationConfigUtils.REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); + } + + public void testMultipleBasePackagesWithDefaultsOnly() { + GenericApplicationContext singlePackageContext = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner singlePackageScanner = new ClassPathBeanDefinitionScanner(singlePackageContext); + GenericApplicationContext multiPackageContext = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner multiPackageScanner = new ClassPathBeanDefinitionScanner(multiPackageContext); + int singlePackageBeanCount = singlePackageScanner.scan(BASE_PACKAGE); + assertEquals(13, singlePackageBeanCount); + int multiPackageBeanCount = multiPackageScanner.scan( + BASE_PACKAGE, "org.springframework.dao.annotation"); + assertTrue(multiPackageBeanCount > singlePackageBeanCount); + } + + public void testMultipleScanCalls() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(13, beanCount); + assertEquals(beanCount, context.getBeanDefinitionCount()); + int addedBeanCount = scanner.scan("org.springframework.aop.aspectj.annotation"); + assertEquals(beanCount + addedBeanCount, context.getBeanDefinitionCount()); + } + + public void testBeanAutowiredWithAnnotationConfigEnabled() { + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBeanDefinition("myBf", new RootBeanDefinition(StaticListableBeanFactory.class)); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + scanner.setBeanNameGenerator(new TestBeanNameGenerator()); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(13, beanCount); + context.refresh(); + + FooServiceImpl fooService = (FooServiceImpl) context.getBean("fooService"); + StaticListableBeanFactory myBf = (StaticListableBeanFactory) context.getBean("myBf"); + MessageSource ms = (MessageSource) context.getBean("messageSource"); + assertTrue(fooService.isInitCalled()); + assertEquals("bar", fooService.foo(123)); + assertSame(context.getDefaultListableBeanFactory(), fooService.beanFactory); + assertEquals(2, fooService.listableBeanFactory.size()); + assertSame(context.getDefaultListableBeanFactory(), fooService.listableBeanFactory.get(0)); + assertSame(myBf, fooService.listableBeanFactory.get(1)); + assertSame(context, fooService.resourceLoader); + assertSame(context, fooService.resourcePatternResolver); + assertSame(context, fooService.eventPublisher); + assertSame(ms, fooService.messageSource); + assertSame(context, fooService.context); + assertEquals(1, fooService.configurableContext.length); + assertSame(context, fooService.configurableContext[0]); + assertSame(context, fooService.genericContext); + } + + public void testBeanNotAutowiredWithAnnotationConfigDisabled() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + scanner.setIncludeAnnotationConfig(false); + scanner.setBeanNameGenerator(new TestBeanNameGenerator()); + int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(9, beanCount); + context.refresh(); + FooService fooService = (FooService) context.getBean("fooService"); + assertFalse(fooService.isInitCalled()); + try { + fooService.foo(123); + fail("NullPointerException expected; fooDao must not have been set"); + } + catch (NullPointerException expected) { + } + } + + public void testAutowireCandidatePatternMatches() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + scanner.setIncludeAnnotationConfig(true); + scanner.setBeanNameGenerator(new TestBeanNameGenerator()); + scanner.setAutowireCandidatePatterns(new String[] { "*FooDao" }); + scanner.scan(BASE_PACKAGE); + context.refresh(); + FooService fooService = (FooService) context.getBean("fooService"); + assertEquals("bar", fooService.foo(123)); + } + + public void testAutowireCandidatePatternDoesNotMatch() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + scanner.setIncludeAnnotationConfig(true); + scanner.setBeanNameGenerator(new TestBeanNameGenerator()); + scanner.setAutowireCandidatePatterns(new String[] { "*NoSuchDao" }); + scanner.scan(BASE_PACKAGE); + try { + context.refresh(); + fail("BeanCreationException expected; fooDao should not have been an autowire-candidate"); + } + catch (BeanCreationException expected) { + assertTrue(expected.getMostSpecificCause() instanceof NoSuchBeanDefinitionException); + } + } + + + private static class TestBeanNameGenerator extends AnnotationBeanNameGenerator { + + @Override + public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { + String beanName = super.generateBeanName(definition, registry); + return beanName.replace("Impl", ""); + } + } + + + @Component("toBeIgnored") + public class NonStaticInnerClass { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java new file mode 100644 index 00000000000..bc5cee3de73 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java @@ -0,0 +1,149 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import java.util.Iterator; +import java.util.Set; +import java.util.regex.Pattern; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.core.type.filter.AssignableTypeFilter; +import org.springframework.core.type.filter.RegexPatternTypeFilter; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Controller; +import org.springframework.stereotype.Repository; +import org.springframework.stereotype.Service; +import org.springframework.util.ClassUtils; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +public class ClassPathScanningCandidateComponentProviderTests extends TestCase { + + private static final String TEST_BASE_PACKAGE = + ClassPathScanningCandidateComponentProviderTests.class.getPackage().getName(); + + + public void testWithDefaults() { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true); + Set candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE); + assertEquals(9, candidates.size()); + assertTrue(containsBeanClass(candidates, NamedComponent.class)); + assertTrue(containsBeanClass(candidates, FooServiceImpl.class)); + assertTrue(containsBeanClass(candidates, StubFooDao.class)); + assertTrue(containsBeanClass(candidates, NamedStubDao.class)); + assertTrue(containsBeanClass(candidates, ServiceInvocationCounter.class)); + } + + public void testWithBogusBasePackage() { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true); + Set candidates = provider.findCandidateComponents("bogus"); + assertEquals(0, candidates.size()); + } + + public void testWithPackageExcludeFilter() { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true); + provider.addExcludeFilter(new RegexPatternTypeFilter(Pattern.compile(TEST_BASE_PACKAGE + ".*"))); + Set candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE); + assertEquals(0, candidates.size()); + } + + public void testWithNoFilters() { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); + Set candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE); + assertEquals(0, candidates.size()); + } + + public void testWithComponentAnnotationOnly() { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); + provider.addIncludeFilter(new AnnotationTypeFilter(Component.class)); + provider.addExcludeFilter(new AnnotationTypeFilter(Repository.class)); + provider.addExcludeFilter(new AnnotationTypeFilter(Service.class)); + provider.addExcludeFilter(new AnnotationTypeFilter(Controller.class)); + Set candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE); + assertEquals(6, candidates.size()); + assertTrue(containsBeanClass(candidates, NamedComponent.class)); + assertTrue(containsBeanClass(candidates, ServiceInvocationCounter.class)); + assertFalse(containsBeanClass(candidates, FooServiceImpl.class)); + assertFalse(containsBeanClass(candidates, StubFooDao.class)); + assertFalse(containsBeanClass(candidates, NamedStubDao.class)); + } + + @SuppressWarnings("unchecked") + public void testWithAspectAnnotationOnly() throws Exception { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); + provider.addIncludeFilter(new AnnotationTypeFilter( + ClassUtils.forName("org.aspectj.lang.annotation.Aspect"))); + Set candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE); + assertEquals(1, candidates.size()); + assertTrue(containsBeanClass(candidates, ServiceInvocationCounter.class)); + } + + public void testWithInterfaceType() { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); + provider.addIncludeFilter(new AssignableTypeFilter(FooDao.class)); + Set candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE); + assertEquals(1, candidates.size()); + assertTrue(containsBeanClass(candidates, StubFooDao.class)); + } + + public void testWithClassType() { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); + provider.addIncludeFilter(new AssignableTypeFilter(MessageBean.class)); + Set candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE); + assertEquals(1, candidates.size()); + assertTrue(containsBeanClass(candidates, MessageBean.class)); + } + + public void testWithMultipleMatchingFilters() { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); + provider.addIncludeFilter(new AnnotationTypeFilter(Component.class)); + provider.addIncludeFilter(new AssignableTypeFilter(FooServiceImpl.class)); + Set candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE); + assertEquals(9, candidates.size()); + assertTrue(containsBeanClass(candidates, NamedComponent.class)); + assertTrue(containsBeanClass(candidates, ServiceInvocationCounter.class)); + assertTrue(containsBeanClass(candidates, FooServiceImpl.class)); + } + + public void testExcludeTakesPrecedence() { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); + provider.addIncludeFilter(new AnnotationTypeFilter(Component.class)); + provider.addIncludeFilter(new AssignableTypeFilter(FooServiceImpl.class)); + provider.addExcludeFilter(new AssignableTypeFilter(FooService.class)); + Set candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE); + assertEquals(8, candidates.size()); + assertTrue(containsBeanClass(candidates, NamedComponent.class)); + assertTrue(containsBeanClass(candidates, ServiceInvocationCounter.class)); + assertFalse(containsBeanClass(candidates, FooServiceImpl.class)); + } + + private boolean containsBeanClass(Set candidates, Class beanClass) { + for (Iterator it = candidates.iterator(); it.hasNext();) { + ScannedGenericBeanDefinition definition = (ScannedGenericBeanDefinition) it.next(); + if (beanClass.getName().equals(definition.getBeanClassName())) { + return true; + } + } + return false; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java new file mode 100644 index 00000000000..af4a28c1ad2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java @@ -0,0 +1,470 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.annotation.Resource; +import javax.ejb.EJB; + +import junit.framework.TestCase; + +import org.springframework.beans.INestedTestBean; +import org.springframework.beans.ITestBean; +import org.springframework.beans.NestedTestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.jndi.support.SimpleJndiBeanFactory; +import org.springframework.mock.jndi.ExpectedLookupTemplate; +import org.springframework.util.SerializationTestUtils; + +/** + * @author Juergen Hoeller + */ +public class CommonAnnotationBeanPostProcessorTests extends TestCase { + + public void testPostConstructAndPreDestroy() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor()); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(AnnotatedInitDestroyBean.class)); + + AnnotatedInitDestroyBean bean = (AnnotatedInitDestroyBean) bf.getBean("annotatedBean"); + assertTrue(bean.initCalled); + bf.destroySingletons(); + assertTrue(bean.destroyCalled); + } + + public void testPostConstructAndPreDestroyWithManualConfiguration() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + InitDestroyAnnotationBeanPostProcessor bpp = new InitDestroyAnnotationBeanPostProcessor(); + bpp.setInitAnnotationType(PostConstruct.class); + bpp.setDestroyAnnotationType(PreDestroy.class); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(AnnotatedInitDestroyBean.class)); + + AnnotatedInitDestroyBean bean = (AnnotatedInitDestroyBean) bf.getBean("annotatedBean"); + assertTrue(bean.initCalled); + bf.destroySingletons(); + assertTrue(bean.destroyCalled); + } + + public void testSerialization() throws Exception { + CommonAnnotationBeanPostProcessor bpp = new CommonAnnotationBeanPostProcessor(); + CommonAnnotationBeanPostProcessor bpp2 = (CommonAnnotationBeanPostProcessor) + SerializationTestUtils.serializeAndDeserialize(bpp); + + AnnotatedInitDestroyBean bean = new AnnotatedInitDestroyBean(); + bpp2.postProcessBeforeDestruction(bean, "annotatedBean"); + assertTrue(bean.destroyCalled); + } + + public void testSerializationWithManualConfiguration() throws Exception { + InitDestroyAnnotationBeanPostProcessor bpp = new InitDestroyAnnotationBeanPostProcessor(); + bpp.setInitAnnotationType(PostConstruct.class); + bpp.setDestroyAnnotationType(PreDestroy.class); + InitDestroyAnnotationBeanPostProcessor bpp2 = (InitDestroyAnnotationBeanPostProcessor) + SerializationTestUtils.serializeAndDeserialize(bpp); + + AnnotatedInitDestroyBean bean = new AnnotatedInitDestroyBean(); + bpp2.postProcessBeforeDestruction(bean, "annotatedBean"); + assertTrue(bean.destroyCalled); + } + + public void testResourceInjection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + CommonAnnotationBeanPostProcessor bpp = new CommonAnnotationBeanPostProcessor(); + bpp.setResourceFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ResourceInjectionBean.class)); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + TestBean tb2 = new TestBean(); + bf.registerSingleton("testBean2", tb2); + + ResourceInjectionBean bean = (ResourceInjectionBean) bf.getBean("annotatedBean"); + assertTrue(bean.initCalled); + assertTrue(bean.init2Called); + assertSame(tb, bean.getTestBean()); + assertSame(tb2, bean.getTestBean2()); + bf.destroySingletons(); + assertTrue(bean.destroyCalled); + assertTrue(bean.destroy2Called); + } + + public void testResourceInjectionWithTwoProcessors() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + CommonAnnotationBeanPostProcessor bpp = new CommonAnnotationBeanPostProcessor(); + bpp.setResourceFactory(bf); + bf.addBeanPostProcessor(bpp); + CommonAnnotationBeanPostProcessor bpp2 = new CommonAnnotationBeanPostProcessor(); + bpp2.setResourceFactory(bf); + bf.addBeanPostProcessor(bpp2); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ResourceInjectionBean.class)); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + TestBean tb2 = new TestBean(); + bf.registerSingleton("testBean2", tb2); + + ResourceInjectionBean bean = (ResourceInjectionBean) bf.getBean("annotatedBean"); + assertTrue(bean.initCalled); + assertTrue(bean.init2Called); + assertSame(tb, bean.getTestBean()); + assertSame(tb2, bean.getTestBean2()); + bf.destroySingletons(); + assertTrue(bean.destroyCalled); + assertTrue(bean.destroy2Called); + } + + public void testResourceInjectionFromJndi() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + CommonAnnotationBeanPostProcessor bpp = new CommonAnnotationBeanPostProcessor(); + SimpleJndiBeanFactory resourceFactory = new SimpleJndiBeanFactory(); + ExpectedLookupTemplate jndiTemplate = new ExpectedLookupTemplate(); + TestBean tb = new TestBean(); + jndiTemplate.addObject("java:comp/env/testBean", tb); + TestBean tb2 = new TestBean(); + jndiTemplate.addObject("java:comp/env/testBean2", tb2); + resourceFactory.setJndiTemplate(jndiTemplate); + bpp.setResourceFactory(resourceFactory); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ResourceInjectionBean.class)); + + ResourceInjectionBean bean = (ResourceInjectionBean) bf.getBean("annotatedBean"); + assertTrue(bean.initCalled); + assertTrue(bean.init2Called); + assertSame(tb, bean.getTestBean()); + assertSame(tb2, bean.getTestBean2()); + bf.destroySingletons(); + assertTrue(bean.destroyCalled); + assertTrue(bean.destroy2Called); + } + + public void testExtendedResourceInjection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + CommonAnnotationBeanPostProcessor bpp = new CommonAnnotationBeanPostProcessor(); + bpp.setResourceFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerResolvableDependency(BeanFactory.class, bf); + + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ExtendedResourceInjectionBean.class)); + bf.registerBeanDefinition("annotatedBean2", new RootBeanDefinition(NamedResourceInjectionBean.class)); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + TestBean tb2 = new TestBean(); + bf.registerSingleton("testBean2", tb2); + TestBean tb3 = new TestBean(); + bf.registerSingleton("testBean3", tb3); + TestBean tb4 = new TestBean(); + bf.registerSingleton("testBean4", tb4); + NestedTestBean tb6 = new NestedTestBean(); + bf.registerSingleton("xy", tb6); + bf.registerAlias("xy", "testBean9"); + + ExtendedResourceInjectionBean bean = (ExtendedResourceInjectionBean) bf.getBean("annotatedBean"); + assertTrue(bean.initCalled); + assertTrue(bean.init2Called); + assertSame(tb, bean.getTestBean()); + assertSame(tb2, bean.getTestBean2()); + assertSame(tb4, bean.getTestBean3()); + assertSame(tb3, bean.getTestBean4()); + assertSame(tb6, bean.testBean5); + assertSame(tb6, bean.testBean6); + assertSame(bf, bean.beanFactory); + + NamedResourceInjectionBean bean2 = (NamedResourceInjectionBean) bf.getBean("annotatedBean2"); + assertSame(tb6, bean2.testBean); + + bf.destroySingletons(); + assertTrue(bean.destroyCalled); + assertTrue(bean.destroy2Called); + } + + public void testExtendedResourceInjectionWithOverriding() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + CommonAnnotationBeanPostProcessor bpp = new CommonAnnotationBeanPostProcessor(); + bpp.setResourceFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerResolvableDependency(BeanFactory.class, bf); + + RootBeanDefinition annotatedBd = new RootBeanDefinition(ExtendedResourceInjectionBean.class); + TestBean tb5 = new TestBean(); + annotatedBd.getPropertyValues().addPropertyValue("testBean2", tb5); + bf.registerBeanDefinition("annotatedBean", annotatedBd); + bf.registerBeanDefinition("annotatedBean2", new RootBeanDefinition(NamedResourceInjectionBean.class)); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + TestBean tb2 = new TestBean(); + bf.registerSingleton("testBean2", tb2); + TestBean tb3 = new TestBean(); + bf.registerSingleton("testBean3", tb3); + TestBean tb4 = new TestBean(); + bf.registerSingleton("testBean4", tb4); + NestedTestBean tb6 = new NestedTestBean(); + bf.registerSingleton("xy", tb6); + + ExtendedResourceInjectionBean bean = (ExtendedResourceInjectionBean) bf.getBean("annotatedBean"); + assertTrue(bean.initCalled); + assertTrue(bean.init2Called); + assertSame(tb, bean.getTestBean()); + assertSame(tb5, bean.getTestBean2()); + assertSame(tb4, bean.getTestBean3()); + assertSame(tb3, bean.getTestBean4()); + assertSame(tb6, bean.testBean5); + assertSame(tb6, bean.testBean6); + assertSame(bf, bean.beanFactory); + + try { + bf.getBean("annotatedBean2"); + } + catch (BeanCreationException ex) { + assertTrue(ex.getRootCause() instanceof NoSuchBeanDefinitionException); + NoSuchBeanDefinitionException innerEx = (NoSuchBeanDefinitionException) ex.getRootCause(); + assertEquals("testBean9", innerEx.getBeanName()); + } + + bf.destroySingletons(); + assertTrue(bean.destroyCalled); + assertTrue(bean.destroy2Called); + } + + public void testExtendedEjbInjection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + CommonAnnotationBeanPostProcessor bpp = new CommonAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerResolvableDependency(BeanFactory.class, bf); + + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ExtendedEjbInjectionBean.class)); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + TestBean tb2 = new TestBean(); + bf.registerSingleton("testBean2", tb2); + TestBean tb3 = new TestBean(); + bf.registerSingleton("testBean3", tb3); + TestBean tb4 = new TestBean(); + bf.registerSingleton("testBean4", tb4); + NestedTestBean tb6 = new NestedTestBean(); + bf.registerSingleton("xy", tb6); + bf.registerAlias("xy", "testBean9"); + + ExtendedEjbInjectionBean bean = (ExtendedEjbInjectionBean) bf.getBean("annotatedBean"); + assertTrue(bean.initCalled); + assertTrue(bean.init2Called); + assertSame(tb, bean.getTestBean()); + assertSame(tb2, bean.getTestBean2()); + assertSame(tb4, bean.getTestBean3()); + assertSame(tb3, bean.getTestBean4()); + assertSame(tb6, bean.testBean5); + assertSame(tb6, bean.testBean6); + assertSame(bf, bean.beanFactory); + + bf.destroySingletons(); + assertTrue(bean.destroyCalled); + assertTrue(bean.destroy2Called); + } + + + public static class AnnotatedInitDestroyBean { + + public boolean initCalled = false; + + public boolean destroyCalled = false; + + @PostConstruct + private void init() { + if (this.initCalled) { + throw new IllegalStateException("Already called"); + } + this.initCalled = true; + } + + @PreDestroy + private void destroy() { + if (this.destroyCalled) { + throw new IllegalStateException("Already called"); + } + this.destroyCalled = true; + } + } + + + public static class ResourceInjectionBean extends AnnotatedInitDestroyBean { + + public boolean init2Called = false; + + public boolean destroy2Called = false; + + @Resource + private TestBean testBean; + + private TestBean testBean2; + + @PostConstruct + protected void init2() { + if (this.testBean == null || this.testBean2 == null) { + throw new IllegalStateException("Resources not injected"); + } + if (this.init2Called) { + throw new IllegalStateException("Already called"); + } + this.init2Called = true; + } + + @PreDestroy + protected void destroy2() { + if (this.destroy2Called) { + throw new IllegalStateException("Already called"); + } + this.destroy2Called = true; + } + + @Resource + public void setTestBean2(TestBean testBean2) { + if (this.testBean2 != null) { + throw new IllegalStateException("Already called"); + } + this.testBean2 = testBean2; + } + + public TestBean getTestBean() { + return testBean; + } + + public TestBean getTestBean2() { + return testBean2; + } + } + + + public static class ExtendedResourceInjectionBean extends ResourceInjectionBean { + + @Resource(name="testBean4", type=TestBean.class) + protected ITestBean testBean3; + + private ITestBean testBean4; + + @Resource + private INestedTestBean testBean5; + + private INestedTestBean testBean6; + + @Resource + private BeanFactory beanFactory; + + @Resource + public void setTestBean2(TestBean testBean2) { + super.setTestBean2(testBean2); + } + + @Resource(name="testBean3", type=ITestBean.class) + private void setTestBean4(ITestBean testBean4) { + this.testBean4 = testBean4; + } + + @Resource + public void setTestBean6(INestedTestBean testBean6) { + this.testBean6 = testBean6; + } + + public ITestBean getTestBean3() { + return testBean3; + } + + public ITestBean getTestBean4() { + return testBean4; + } + + @PostConstruct + protected void init2() { + if (this.testBean3 == null || this.testBean4 == null) { + throw new IllegalStateException("Resources not injected"); + } + super.init2(); + } + + @PreDestroy + protected void destroy2() { + super.destroy2(); + } + } + + + public static class ExtendedEjbInjectionBean extends ResourceInjectionBean { + + @EJB(name="testBean4", beanInterface=TestBean.class) + protected ITestBean testBean3; + + private ITestBean testBean4; + + @EJB + private INestedTestBean testBean5; + + private INestedTestBean testBean6; + + @Resource + private BeanFactory beanFactory; + + @EJB + public void setTestBean2(TestBean testBean2) { + super.setTestBean2(testBean2); + } + + @EJB(beanName="testBean3", beanInterface=ITestBean.class) + private void setTestBean4(ITestBean testBean4) { + this.testBean4 = testBean4; + } + + @EJB + public void setTestBean6(INestedTestBean testBean6) { + this.testBean6 = testBean6; + } + + public ITestBean getTestBean3() { + return testBean3; + } + + public ITestBean getTestBean4() { + return testBean4; + } + + @PostConstruct + protected void init2() { + if (this.testBean3 == null || this.testBean4 == null) { + throw new IllegalStateException("Resources not injected"); + } + super.init2(); + } + + @PreDestroy + protected void destroy2() { + super.destroy2(); + } + } + + + private static class NamedResourceInjectionBean { + + @Resource(name="testBean9") + private INestedTestBean testBean; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserBeanDefinitionDefaultsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserBeanDefinitionDefaultsTests.java new file mode 100644 index 00000000000..43a0448835e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserBeanDefinitionDefaultsTests.java @@ -0,0 +1,288 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.UnsatisfiedDependencyException; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.context.support.GenericApplicationContext; + +/** + * @author Mark Fisher + */ +public class ComponentScanParserBeanDefinitionDefaultsTests extends TestCase { + + private static final String TEST_BEAN_NAME = "componentScanParserBeanDefinitionDefaultsTests.DefaultsTestBean"; + + private static final String LOCATION_PREFIX = "org/springframework/context/annotation/"; + + + public void setUp() { + DefaultsTestBean.INIT_COUNT = 0; + } + + public void testDefaultLazyInit() { + GenericApplicationContext context = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultWithNoOverridesTests.xml"); + assertFalse("lazy-init should be false", context.getBeanDefinition(TEST_BEAN_NAME).isLazyInit()); + assertEquals("initCount should be 0", 0, DefaultsTestBean.INIT_COUNT); + context.refresh(); + assertEquals("bean should have been instantiated", 1, DefaultsTestBean.INIT_COUNT); + } + + public void testLazyInitTrue() { + GenericApplicationContext context = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultLazyInitTrueTests.xml"); + assertTrue("lazy-init should be true", context.getBeanDefinition(TEST_BEAN_NAME).isLazyInit()); + assertEquals("initCount should be 0", 0, DefaultsTestBean.INIT_COUNT); + context.refresh(); + assertEquals("bean should not have been instantiated yet", 0, DefaultsTestBean.INIT_COUNT); + context.getBean(TEST_BEAN_NAME); + assertEquals("bean should have been instantiated", 1, DefaultsTestBean.INIT_COUNT); + } + + public void testLazyInitFalse() { + GenericApplicationContext context = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultLazyInitFalseTests.xml"); + assertFalse("lazy-init should be false", context.getBeanDefinition(TEST_BEAN_NAME).isLazyInit()); + assertEquals("initCount should be 0", 0, DefaultsTestBean.INIT_COUNT); + context.refresh(); + assertEquals("bean should have been instantiated", 1, DefaultsTestBean.INIT_COUNT); + } + + public void testDefaultAutowire() { + GenericApplicationContext context = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultWithNoOverridesTests.xml"); + context.refresh(); + DefaultsTestBean bean = (DefaultsTestBean) context.getBean(TEST_BEAN_NAME); + assertNull("no dependencies should have been autowired", bean.getConstructorDependency()); + assertNull("no dependencies should have been autowired", bean.getPropertyDependency1()); + assertNull("no dependencies should have been autowired", bean.getPropertyDependency2()); + } + + public void testAutowireNo() { + GenericApplicationContext context = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultAutowireNoTests.xml"); + context.refresh(); + DefaultsTestBean bean = (DefaultsTestBean) context.getBean(TEST_BEAN_NAME); + assertNull("no dependencies should have been autowired", bean.getConstructorDependency()); + assertNull("no dependencies should have been autowired", bean.getPropertyDependency1()); + assertNull("no dependencies should have been autowired", bean.getPropertyDependency2()); + } + + public void testAutowireConstructor() { + GenericApplicationContext context = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultAutowireConstructorTests.xml"); + context.refresh(); + DefaultsTestBean bean = (DefaultsTestBean) context.getBean(TEST_BEAN_NAME); + assertNotNull("constructor dependency should have been autowired", bean.getConstructorDependency()); + assertEquals("cd", bean.getConstructorDependency().getName()); + assertNull("property dependencies should not have been autowired", bean.getPropertyDependency1()); + assertNull("property dependencies should not have been autowired", bean.getPropertyDependency2()); + } + + public void testAutowireByType() { + GenericApplicationContext context = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultAutowireByTypeTests.xml"); + try { + context.refresh(); + fail("expected exception due to multiple matches for byType autowiring"); + } + catch (UnsatisfiedDependencyException e) { + // expected + } + } + + public void testAutowireByName() { + GenericApplicationContext context = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultAutowireByNameTests.xml"); + context.refresh(); + DefaultsTestBean bean = (DefaultsTestBean) context.getBean(TEST_BEAN_NAME); + assertNull("constructor dependency should not have been autowired", bean.getConstructorDependency()); + assertNull("propertyDependency1 should not have been autowired", bean.getPropertyDependency1()); + assertNotNull("propertyDependency2 should have been autowired", bean.getPropertyDependency2()); + assertEquals("pd2", bean.getPropertyDependency2().getName()); + } + + public void testDefaultDependencyCheck() { + GenericApplicationContext context = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultWithNoOverridesTests.xml"); + context.refresh(); + DefaultsTestBean bean = (DefaultsTestBean) context.getBean(TEST_BEAN_NAME); + assertNull("constructor dependency should not have been autowired", bean.getConstructorDependency()); + assertNull("property dependencies should not have been autowired", bean.getPropertyDependency1()); + assertNull("property dependencies should not have been autowired", bean.getPropertyDependency2()); + } + + public void testDependencyCheckAll() { + GenericApplicationContext context = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultDependencyCheckAllTests.xml"); + try { + context.refresh(); + fail("expected exception due to dependency check"); + } + catch (UnsatisfiedDependencyException e) { + // expected + } + } + + public void testDependencyCheckObjectsWithAutowireByName() { + GenericApplicationContext context = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultDependencyCheckObjectsWithAutowireByNameTests.xml"); + context.refresh(); + DefaultsTestBean bean = (DefaultsTestBean) context.getBean(TEST_BEAN_NAME); + assertNull("constructor dependency should not have been autowired", bean.getConstructorDependency()); + assertNotNull("property dependencies should have been autowired", bean.getPropertyDependency1()); + assertNotNull("property dependencies should have been autowired", bean.getPropertyDependency2()); + } + + public void testDefaultInitAndDestroyMethodsNotDefined() { + GenericApplicationContext context = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultWithNoOverridesTests.xml"); + context.refresh(); + DefaultsTestBean bean = (DefaultsTestBean) context.getBean(TEST_BEAN_NAME); + assertFalse("bean should not have been initialized", bean.isInitialized()); + context.close(); + assertFalse("bean should not have been destroyed", bean.isDestroyed()); + } + + public void testDefaultInitAndDestroyMethodsDefined() { + GenericApplicationContext context = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultInitAndDestroyMethodsTests.xml"); + context.refresh(); + DefaultsTestBean bean = (DefaultsTestBean) context.getBean(TEST_BEAN_NAME); + assertTrue("bean should have been initialized", bean.isInitialized()); + context.close(); + assertTrue("bean should have been destroyed", bean.isDestroyed()); + } + + public void testDefaultNonExistingInitAndDestroyMethodsDefined() { + GenericApplicationContext context = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultNonExistingInitAndDestroyMethodsTests.xml"); + context.refresh(); + DefaultsTestBean bean = (DefaultsTestBean) context.getBean(TEST_BEAN_NAME); + assertFalse("bean should not have been initialized", bean.isInitialized()); + context.close(); + assertFalse("bean should not have been destroyed", bean.isDestroyed()); + } + + + private static class DefaultsTestBean { + + static int INIT_COUNT; + + private ConstructorDependencyTestBean constructorDependency; + + private PropertyDependencyTestBean propertyDependency1; + + private PropertyDependencyTestBean propertyDependency2; + + private boolean initialized; + + private boolean destroyed; + + + public DefaultsTestBean() { + INIT_COUNT++; + } + + public DefaultsTestBean(ConstructorDependencyTestBean cdtb) { + this(); + this.constructorDependency = cdtb; + } + + public void init() { + this.initialized = true; + } + + public boolean isInitialized() { + return this.initialized; + } + + public void destroy() { + this.destroyed = true; + } + + public boolean isDestroyed() { + return this.destroyed; + } + + public void setPropertyDependency1(PropertyDependencyTestBean pdtb) { + this.propertyDependency1 = pdtb; + } + + public void setPropertyDependency2(PropertyDependencyTestBean pdtb) { + this.propertyDependency2 = pdtb; + } + + public ConstructorDependencyTestBean getConstructorDependency() { + return this.constructorDependency; + } + + public PropertyDependencyTestBean getPropertyDependency1() { + return this.propertyDependency1; + } + + public PropertyDependencyTestBean getPropertyDependency2() { + return this.propertyDependency2; + } + } + + + private static class PropertyDependencyTestBean { + + private String name; + + public PropertyDependencyTestBean(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + } + + + private static class ConstructorDependencyTestBean { + + private String name; + + public ConstructorDependencyTestBean(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserScopedProxyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserScopedProxyTests.java new file mode 100644 index 00000000000..4c0b11ff6e0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserScopedProxyTests.java @@ -0,0 +1,80 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import junit.framework.TestCase; + +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.config.SimpleMapScope; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +public class ComponentScanParserScopedProxyTests extends TestCase { + + public void testDefaultScopedProxy() { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/scopedProxyDefaultTests.xml"); + context.getBeanFactory().registerScope("myScope", new SimpleMapScope()); + ScopedProxyTestBean bean = (ScopedProxyTestBean) context.getBean("scopedProxyTestBean"); + // should not be a proxy + assertFalse(AopUtils.isAopProxy(bean)); + } + + public void testNoScopedProxy() { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/scopedProxyNoTests.xml"); + context.getBeanFactory().registerScope("myScope", new SimpleMapScope()); + ScopedProxyTestBean bean = (ScopedProxyTestBean) context.getBean("scopedProxyTestBean"); + // should not be a proxy + assertFalse(AopUtils.isAopProxy(bean)); + } + + public void testInterfacesScopedProxy() { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/scopedProxyInterfacesTests.xml"); + context.getBeanFactory().registerScope("myScope", new SimpleMapScope()); + // should cast to the interface + FooService bean = (FooService) context.getBean("scopedProxyTestBean"); + // should be dynamic proxy + assertTrue(AopUtils.isJdkDynamicProxy(bean)); + } + + public void testTargetClassScopedProxy() { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/scopedProxyTargetClassTests.xml"); + context.getBeanFactory().registerScope("myScope", new SimpleMapScope()); + ScopedProxyTestBean bean = (ScopedProxyTestBean) context.getBean("scopedProxyTestBean"); + // should be a class-based proxy + assertTrue(AopUtils.isCglibProxy(bean)); + } + + public void testInvalidConfigScopedProxy() { + try { + new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/scopedProxyInvalidConfigTests.xml"); + fail("should have thrown Exception; scope-resolver and scoped-proxy both provided"); + } + catch (FatalBeanException e) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserTests.java new file mode 100644 index 00000000000..6d99e468700 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserTests.java @@ -0,0 +1,112 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +public class ComponentScanParserTests extends TestCase { + + public void testAspectJTypeFilter() { + ApplicationContext context = new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/aspectjTypeFilterTests.xml"); + assertTrue(context.containsBean("fooServiceImpl")); + assertTrue(context.containsBean("stubFooDao")); + assertFalse(context.containsBean("scopedProxyTestBean")); + } + + public void testNonMatchingResourcePattern() { + ApplicationContext context = new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/nonMatchingResourcePatternTests.xml"); + assertFalse(context.containsBean("fooServiceImpl")); + } + + public void testMatchingResourcePattern() { + ApplicationContext context = new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/matchingResourcePatternTests.xml"); + assertTrue(context.containsBean("fooServiceImpl")); + } + + public void testComponentScanWithAutowiredQualifier() { + ApplicationContext context = new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/componentScanWithAutowiredQualifierTests.xml"); + AutowiredQualifierFooService fooService = (AutowiredQualifierFooService) context.getBean("fooService"); + assertTrue(fooService.isInitCalled()); + assertEquals("bar", fooService.foo(123)); + } + + public void testCustomAnnotationUsedForBothComponentScanAndQualifier() { + ApplicationContext context = new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/customAnnotationUsedForBothComponentScanAndQualifierTests.xml"); + CustomAnnotationAutowiredBean testBean = (CustomAnnotationAutowiredBean) context.getBean("testBean"); + assertNotNull(testBean.getDependency()); + } + + public void testCustomTypeFilter() { + ApplicationContext context = new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/customTypeFilterTests.xml"); + CustomAnnotationAutowiredBean testBean = (CustomAnnotationAutowiredBean) context.getBean("testBean"); + assertNotNull(testBean.getDependency()); + } + + + @Target({ElementType.TYPE, ElementType.FIELD}) + @Retention(RetentionPolicy.RUNTIME) + public static @interface CustomAnnotation { + } + + + public static class CustomAnnotationAutowiredBean { + + @Autowired + @CustomAnnotation + private CustomAnnotationDependencyBean dependency; + + public CustomAnnotationDependencyBean getDependency() { + return this.dependency; + } + } + + + @CustomAnnotation + public static class CustomAnnotationDependencyBean { + } + + + public static class CustomTypeFilter implements TypeFilter { + + public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) { + return metadataReader.getClassMetadata().getClassName().contains("Custom"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserWithUserDefinedStrategiesTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserWithUserDefinedStrategiesTests.java new file mode 100644 index 00000000000..cd64a0148d1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ComponentScanParserWithUserDefinedStrategiesTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Mark Fisher + */ +public class ComponentScanParserWithUserDefinedStrategiesTests extends AbstractDependencyInjectionSpringContextTests { + + public void testCustomBeanNameGenerator() { + ApplicationContext context = new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/customNameGeneratorTests.xml"); + assertTrue(context.containsBean("testing.fooServiceImpl")); + } + + public void testCustomScopeMetadataResolver() { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/customScopeResolverTests.xml"); + BeanDefinition bd = context.getBeanFactory().getBeanDefinition("fooServiceImpl"); + assertEquals("myCustomScope", bd.getScope()); + assertFalse(bd.isSingleton()); + } + + public void testInvalidConstructorBeanNameGenerator() { + try { + new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/invalidConstructorNameGeneratorTests.xml"); + fail("should have failed: no-arg constructor is required"); + } + catch (BeansException e) { + // expected + } + } + + public void testInvalidClassNameScopeMetadataResolver() { + try { + new ClassPathXmlApplicationContext( + "org/springframework/context/annotation/invalidClassNameScopeResolverTests.xml"); + fail("should have failed: no such class"); + } + catch (BeansException e) { + // expected + } + } + +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/CustomComponent.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/CustomComponent.java new file mode 100644 index 00000000000..ad9796ca2b4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/CustomComponent.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Mark Fisher + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface CustomComponent { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/CustomStereotype.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/CustomStereotype.java new file mode 100644 index 00000000000..b0b471a3171 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/CustomStereotype.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.stereotype.Component; + +/** + * @author Juergen Hoeller + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Component +public @interface CustomStereotype { + + String value() default "thoreau"; + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/DefaultNamedComponent.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/DefaultNamedComponent.java new file mode 100644 index 00000000000..52693697a67 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/DefaultNamedComponent.java @@ -0,0 +1,27 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import org.springframework.stereotype.Component; + +/** + * @author Juergen Hoeller + */ +@CustomStereotype +public class DefaultNamedComponent { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/DoubleScanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/DoubleScanTests.java new file mode 100644 index 00000000000..e69956009e1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/DoubleScanTests.java @@ -0,0 +1,29 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +/** + * @author Juergen Hoeller + */ +public class DoubleScanTests extends SimpleScanTests { + + @Override + protected String[] getConfigLocations() { + return new String[] {"org/springframework/context/annotation/doubleScanTests.xml"}; + } + +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/FooDao.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/FooDao.java new file mode 100644 index 00000000000..43964259763 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/FooDao.java @@ -0,0 +1,26 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +/** + * @author Mark Fisher + */ +public interface FooDao { + + String findFoo(int id); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/FooService.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/FooService.java new file mode 100644 index 00000000000..4082e06cebb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/FooService.java @@ -0,0 +1,29 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +public interface FooService { + + String foo(int id); + + boolean isInitCalled(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/FooServiceImpl.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/FooServiceImpl.java new file mode 100644 index 00000000000..5eb3a0a1549 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/FooServiceImpl.java @@ -0,0 +1,80 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import java.util.List; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.MessageSource; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.stereotype.Service; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +@Service +public class FooServiceImpl implements FooService { + + @Autowired private FooDao fooDao; + + @Autowired public BeanFactory beanFactory; + + @Autowired public List listableBeanFactory; + + @Autowired public ResourceLoader resourceLoader; + + @Autowired public ResourcePatternResolver resourcePatternResolver; + + @Autowired public ApplicationEventPublisher eventPublisher; + + @Autowired public MessageSource messageSource; + + @Autowired public ApplicationContext context; + + @Autowired public ConfigurableApplicationContext[] configurableContext; + + @Autowired public AbstractApplicationContext genericContext; + + private boolean initCalled = false; + + @PostConstruct + private void init() { + if (this.initCalled) { + throw new IllegalStateException("Init already called"); + } + this.initCalled = true; + } + + public String foo(int id) { + return this.fooDao.findFoo(id); + } + + public boolean isInitCalled() { + return this.initCalled; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/InvalidConstructorTestBeanNameGenerator.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/InvalidConstructorTestBeanNameGenerator.java new file mode 100644 index 00000000000..f79335ecfcc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/InvalidConstructorTestBeanNameGenerator.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanNameGenerator; + +/** + * @author Mark Fisher + */ +public class InvalidConstructorTestBeanNameGenerator implements BeanNameGenerator { + + public InvalidConstructorTestBeanNameGenerator(String s) { + // a no-arg constructor is required + } + + public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { + return null; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/MessageBean.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/MessageBean.java new file mode 100644 index 00000000000..be9c68bda2f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/MessageBean.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +/** + * @author Mark Fisher + */ +@CustomComponent +public class MessageBean { + + private String message; + + public MessageBean() { + this.message = "DEFAULT MESSAGE"; + } + + public MessageBean(String message) { + this.message = message; + } + + public String getMessage() { + return this.message; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/NamedComponent.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/NamedComponent.java new file mode 100644 index 00000000000..8bcb205765f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/NamedComponent.java @@ -0,0 +1,27 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import org.springframework.stereotype.Component; + +/** + * @author Mark Fisher + */ +@Component("myNamedComponent") +public class NamedComponent { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/NamedStubDao.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/NamedStubDao.java new file mode 100644 index 00000000000..a15ae5b2167 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/NamedStubDao.java @@ -0,0 +1,31 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import org.springframework.stereotype.Repository; + +/** + * @author Juergen Hoeller + */ +@Repository("myNamedDao") +public class NamedStubDao { + + public String find(int id) { + return "bar"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ScopedProxyTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ScopedProxyTestBean.java new file mode 100644 index 00000000000..71c36b6f825 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ScopedProxyTestBean.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +@Scope("myScope") +public class ScopedProxyTestBean implements FooService { + + public String foo(int id) { + return "bar"; + } + + public boolean isInitCalled() { + return false; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ServiceInvocationCounter.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ServiceInvocationCounter.java new file mode 100644 index 00000000000..ec90390fa94 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ServiceInvocationCounter.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; + +import org.springframework.stereotype.Component; + +/** + * @author Mark Fisher + */ +@Component +@Aspect +public class ServiceInvocationCounter { + + private int useCount; + + @Pointcut("execution(* org.springframework.context.annotation.FooService+.*(..))") + public void serviceExecution() {} + + @Before("serviceExecution()") + public void countUse() { + this.useCount++; + } + + public int getCount() { + return this.useCount; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/SimpleConfigTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/SimpleConfigTests.java new file mode 100644 index 00000000000..c083e53f9ef --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/SimpleConfigTests.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Mark Fisher + */ +public class SimpleConfigTests extends AbstractDependencyInjectionSpringContextTests { + + private FooService fooService; + + private ServiceInvocationCounter serviceInvocationCounter; + + public void setFooService(FooService fooService) { + this.fooService = fooService; + } + + public void setServiceInvocationCounter(ServiceInvocationCounter serviceInvocationCounter) { + this.serviceInvocationCounter = serviceInvocationCounter; + } + + public void testFooService() throws Exception { + String value = fooService.foo(1); + assertEquals("bar", value); + + assertEquals(1, serviceInvocationCounter.getCount()); + + fooService.foo(1); + assertEquals(2, serviceInvocationCounter.getCount()); + } + + @Override + protected String[] getConfigLocations() { + return new String[] {"org/springframework/context/annotation/simpleConfigTests.xml"}; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/SimpleScanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/SimpleScanTests.java new file mode 100644 index 00000000000..b80f583a053 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/SimpleScanTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +public class SimpleScanTests extends AbstractDependencyInjectionSpringContextTests { + + private FooService fooService; + + private ServiceInvocationCounter serviceInvocationCounter; + + + public void setFooService(FooService fooService) { + this.fooService = fooService; + } + + public void setServiceInvocationCounter(ServiceInvocationCounter serviceInvocationCounter) { + this.serviceInvocationCounter = serviceInvocationCounter; + } + + + @Override + protected String[] getConfigLocations() { + return new String[] {"org/springframework/context/annotation/simpleScanTests.xml"}; + } + + + public void testFooService() throws Exception { + assertEquals(0, serviceInvocationCounter.getCount()); + + assertTrue(fooService.isInitCalled()); + assertEquals(1, serviceInvocationCounter.getCount()); + + String value = fooService.foo(1); + assertEquals("bar", value); + assertEquals(2, serviceInvocationCounter.getCount()); + + fooService.foo(1); + assertEquals(3, serviceInvocationCounter.getCount()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/Spr3775InitDestroyLifecycleTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/Spr3775InitDestroyLifecycleTests.java new file mode 100644 index 00000000000..5cd4eb5eaf7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/Spr3775InitDestroyLifecycleTests.java @@ -0,0 +1,261 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import junit.framework.TestCase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.util.ObjectUtils; + +/** + *

+ * JUnit-3.8-based unit test which verifies expected init and + * destroy bean lifecycle behavior as requested in SPR-3775. + *

+ *

+ * Specifically, combinations of the following are tested: + *

+ *
    + *
  • {@link InitializingBean} & {@link DisposableBean} interfaces
  • + *
  • Custom {@link RootBeanDefinition#getInitMethodName() init} & + * {@link RootBeanDefinition#getDestroyMethodName() destroy} methods
  • + *
  • JSR 250's {@link javax.annotation.PostConstruct @PostConstruct} & + * {@link javax.annotation.PreDestroy @PreDestroy} annotations
  • + *
+ * + * @author Sam Brannen + * @since 2.5 + */ +public class Spr3775InitDestroyLifecycleTests extends TestCase { + + private static final Log logger = LogFactory.getLog(Spr3775InitDestroyLifecycleTests.class); + + /** LIFECYCLE_TEST_BEAN. */ + private static final String LIFECYCLE_TEST_BEAN = "lifecycleTestBean"; + + + private void debugMethods(Class clazz, String category, List methodNames) { + if (logger.isDebugEnabled()) { + logger.debug(clazz.getSimpleName() + ": " + category + ": " + methodNames); + } + } + + private void assertMethodOrdering(Class clazz, String category, List expectedMethods, + List actualMethods) { + debugMethods(clazz, category, actualMethods); + assertTrue("Verifying " + category + ": expected<" + expectedMethods + "> but got<" + actualMethods + ">.", + ObjectUtils.nullSafeEquals(expectedMethods, actualMethods)); + } + + private DefaultListableBeanFactory createBeanFactoryAndRegisterBean(final Class beanClass, + final String initMethodName, final String destroyMethodName) { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); + beanDefinition.setInitMethodName(initMethodName); + beanDefinition.setDestroyMethodName(destroyMethodName); + beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor()); + beanFactory.registerBeanDefinition(LIFECYCLE_TEST_BEAN, beanDefinition); + return beanFactory; + } + + public void testInitDestroyMethods() { + final Class beanClass = InitDestroyBean.class; + final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, + "afterPropertiesSet", "destroy"); + final InitDestroyBean bean = (InitDestroyBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); + assertMethodOrdering(beanClass, "init-methods", Arrays.asList("afterPropertiesSet"), bean.initMethods); + beanFactory.destroySingletons(); + assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("destroy"), bean.destroyMethods); + } + + public void testInitializingDisposableInterfaces() { + final Class beanClass = CustomInitializingDisposableBean.class; + final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit", + "customDestroy"); + final CustomInitializingDisposableBean bean = (CustomInitializingDisposableBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); + assertMethodOrdering(beanClass, "init-methods", Arrays.asList("afterPropertiesSet", "customInit"), + bean.initMethods); + beanFactory.destroySingletons(); + assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("destroy", "customDestroy"), + bean.destroyMethods); + } + + public void testInitializingDisposableInterfacesWithShadowedMethods() { + final Class beanClass = InitializingDisposableWithShadowedMethodsBean.class; + final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, + "afterPropertiesSet", "destroy"); + final InitializingDisposableWithShadowedMethodsBean bean = (InitializingDisposableWithShadowedMethodsBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); + assertMethodOrdering(beanClass, "init-methods", Arrays.asList("InitializingBean.afterPropertiesSet"), + bean.initMethods); + beanFactory.destroySingletons(); + assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("DisposableBean.destroy"), bean.destroyMethods); + } + + public void testJsr250Annotations() { + final Class beanClass = CustomAnnotatedInitDestroyBean.class; + final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit", + "customDestroy"); + final CustomAnnotatedInitDestroyBean bean = (CustomAnnotatedInitDestroyBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); + assertMethodOrdering(beanClass, "init-methods", Arrays.asList("postConstruct", "afterPropertiesSet", + "customInit"), bean.initMethods); + beanFactory.destroySingletons(); + assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("preDestroy", "destroy", "customDestroy"), + bean.destroyMethods); + } + + public void testJsr250AnnotationsWithShadowedMethods() { + final Class beanClass = CustomAnnotatedInitDestroyWithShadowedMethodsBean.class; + final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit", + "customDestroy"); + final CustomAnnotatedInitDestroyWithShadowedMethodsBean bean = (CustomAnnotatedInitDestroyWithShadowedMethodsBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); + assertMethodOrdering(beanClass, "init-methods", + Arrays.asList("@PostConstruct.afterPropertiesSet", "customInit"), bean.initMethods); + beanFactory.destroySingletons(); + assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("@PreDestroy.destroy", "customDestroy"), + bean.destroyMethods); + } + + public void testAllLifecycleMechanismsAtOnce() { + final Class beanClass = AllInOneBean.class; + final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, + "afterPropertiesSet", "destroy"); + final AllInOneBean bean = (AllInOneBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); + assertMethodOrdering(beanClass, "init-methods", Arrays.asList("afterPropertiesSet"), bean.initMethods); + beanFactory.destroySingletons(); + assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("destroy"), bean.destroyMethods); + } + + + public static class InitDestroyBean { + + final List initMethods = new ArrayList(); + final List destroyMethods = new ArrayList(); + + + public void afterPropertiesSet() throws Exception { + this.initMethods.add("afterPropertiesSet"); + } + + public void destroy() throws Exception { + this.destroyMethods.add("destroy"); + } + } + + public static class InitializingDisposableWithShadowedMethodsBean extends InitDestroyBean implements + InitializingBean, DisposableBean { + + @Override + public void afterPropertiesSet() throws Exception { + this.initMethods.add("InitializingBean.afterPropertiesSet"); + } + + @Override + public void destroy() throws Exception { + this.destroyMethods.add("DisposableBean.destroy"); + } + } + + + public static class CustomInitDestroyBean { + + final List initMethods = new ArrayList(); + final List destroyMethods = new ArrayList(); + + public void customInit() throws Exception { + this.initMethods.add("customInit"); + } + + public void customDestroy() throws Exception { + this.destroyMethods.add("customDestroy"); + } + } + + + public static class CustomInitializingDisposableBean extends CustomInitDestroyBean + implements InitializingBean, DisposableBean { + + public void afterPropertiesSet() throws Exception { + this.initMethods.add("afterPropertiesSet"); + } + + public void destroy() throws Exception { + this.destroyMethods.add("destroy"); + } + } + + + public static class CustomAnnotatedInitDestroyBean extends CustomInitializingDisposableBean { + + @PostConstruct + public void postConstruct() throws Exception { + this.initMethods.add("postConstruct"); + } + + @PreDestroy + public void preDestroy() throws Exception { + this.destroyMethods.add("preDestroy"); + } + } + + + public static class CustomAnnotatedInitDestroyWithShadowedMethodsBean extends CustomInitializingDisposableBean { + + @PostConstruct + @Override + public void afterPropertiesSet() throws Exception { + this.initMethods.add("@PostConstruct.afterPropertiesSet"); + } + + @PreDestroy + @Override + public void destroy() throws Exception { + this.destroyMethods.add("@PreDestroy.destroy"); + } + } + + + public static class AllInOneBean implements InitializingBean, DisposableBean { + + final List initMethods = new ArrayList(); + final List destroyMethods = new ArrayList(); + + @PostConstruct + public void afterPropertiesSet() throws Exception { + this.initMethods.add("afterPropertiesSet"); + } + + @PreDestroy + public void destroy() throws Exception { + this.destroyMethods.add("destroy"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/StubFooDao.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/StubFooDao.java new file mode 100644 index 00000000000..567c2499925 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/StubFooDao.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Repository; + +/** + * @author Mark Fisher + */ +@Repository +@Qualifier("testing") +public class StubFooDao implements FooDao { + + public String findFoo(int id) { + return "bar"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/TestBeanNameGenerator.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/TestBeanNameGenerator.java new file mode 100644 index 00000000000..1f77d726b9a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/TestBeanNameGenerator.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; + +/** + * @author Mark Fisher + */ +public class TestBeanNameGenerator extends AnnotationBeanNameGenerator { + + public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { + String beanName = super.generateBeanName(definition, registry); + return "testing." + beanName; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/TestScopeMetadataResolver.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/TestScopeMetadataResolver.java new file mode 100644 index 00000000000..5471d438af4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/TestScopeMetadataResolver.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import org.springframework.beans.factory.config.BeanDefinition; + +/** + * @author Mark Fisher + */ +public class TestScopeMetadataResolver implements ScopeMetadataResolver { + + public ScopeMetadata resolveScopeMetadata(BeanDefinition beanDefinition) { + ScopeMetadata metadata = new ScopeMetadata(); + metadata.setScopeName("myCustomScope"); + return metadata; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/aspectjTypeFilterTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/aspectjTypeFilterTests.xml new file mode 100644 index 00000000000..c9c4b27f0f3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/aspectjTypeFilterTests.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/componentScanWithAutowiredQualifierTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/componentScanWithAutowiredQualifierTests.xml new file mode 100644 index 00000000000..014552c2e76 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/componentScanWithAutowiredQualifierTests.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customAnnotationUsedForBothComponentScanAndQualifierTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customAnnotationUsedForBothComponentScanAndQualifierTests.xml new file mode 100644 index 00000000000..922aca4bdd0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customAnnotationUsedForBothComponentScanAndQualifierTests.xml @@ -0,0 +1,22 @@ + + + + + + + + + + org.springframework.context.annotation.ComponentScanParserTests$CustomAnnotation + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customNameGeneratorTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customNameGeneratorTests.xml new file mode 100644 index 00000000000..98afdcf0395 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customNameGeneratorTests.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customScopeResolverTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customScopeResolverTests.xml new file mode 100644 index 00000000000..46ead34fc96 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customScopeResolverTests.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customTypeFilterTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customTypeFilterTests.xml new file mode 100644 index 00000000000..f8c1351fe53 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/customTypeFilterTests.xml @@ -0,0 +1,22 @@ + + + + + + + + + + org.springframework.context.annotation.ComponentScanParserTests$CustomAnnotation + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireByNameTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireByNameTests.xml new file mode 100644 index 00000000000..ea5fd0061c4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireByNameTests.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireByTypeTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireByTypeTests.xml new file mode 100644 index 00000000000..03dc019f40b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireByTypeTests.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireConstructorTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireConstructorTests.xml new file mode 100644 index 00000000000..4431641a7e6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireConstructorTests.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireNoTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireNoTests.xml new file mode 100644 index 00000000000..cd7930f6907 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultAutowireNoTests.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultDependencyCheckAllTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultDependencyCheckAllTests.xml new file mode 100644 index 00000000000..46cbe2adb72 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultDependencyCheckAllTests.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultDependencyCheckObjectsWithAutowireByNameTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultDependencyCheckObjectsWithAutowireByNameTests.xml new file mode 100644 index 00000000000..505cb3b4b4e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultDependencyCheckObjectsWithAutowireByNameTests.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultInitAndDestroyMethodsTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultInitAndDestroyMethodsTests.xml new file mode 100644 index 00000000000..de592f96ee6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultInitAndDestroyMethodsTests.xml @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultLazyInitFalseTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultLazyInitFalseTests.xml new file mode 100644 index 00000000000..b16bae4cda4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultLazyInitFalseTests.xml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultLazyInitTrueTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultLazyInitTrueTests.xml new file mode 100644 index 00000000000..ed11edfa2bf --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultLazyInitTrueTests.xml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultNonExistingInitAndDestroyMethodsTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultNonExistingInitAndDestroyMethodsTests.xml new file mode 100644 index 00000000000..eca6cd8cf84 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultNonExistingInitAndDestroyMethodsTests.xml @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultWithNoOverridesTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultWithNoOverridesTests.xml new file mode 100644 index 00000000000..adfc3aa442b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/defaultWithNoOverridesTests.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/doubleScanTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/doubleScanTests.xml new file mode 100644 index 00000000000..ceafc590f6a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/doubleScanTests.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/invalidClassNameScopeResolverTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/invalidClassNameScopeResolverTests.xml new file mode 100644 index 00000000000..d4f509b4beb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/invalidClassNameScopeResolverTests.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/invalidConstructorNameGeneratorTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/invalidConstructorNameGeneratorTests.xml new file mode 100644 index 00000000000..3bde5e6ac51 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/invalidConstructorNameGeneratorTests.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ltw/ComponentScanningWithLTWTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ltw/ComponentScanningWithLTWTests.java new file mode 100644 index 00000000000..afbcab7a28b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ltw/ComponentScanningWithLTWTests.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation.ltw; + +import org.springframework.test.jpa.AbstractJpaTests; + +/** + * Test to ensure that component scanning work with load-time weaver. + * See SPR-3873 for more details. + * + * @author Ramnivas Laddad + */ +public class ComponentScanningWithLTWTests extends AbstractJpaTests { + + public ComponentScanningWithLTWTests() { + setDependencyCheck(false); + } + + @Override + protected String getConfigPath() { + return "ComponentScanningWithLTWTests.xml"; + } + + public void testLoading() { + // do nothing as successful loading is the test + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ltw/ComponentScanningWithLTWTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ltw/ComponentScanningWithLTWTests.xml new file mode 100644 index 00000000000..d16a4c3ef3a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/ltw/ComponentScanningWithLTWTests.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/matchingResourcePatternTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/matchingResourcePatternTests.xml new file mode 100644 index 00000000000..666cedeb216 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/matchingResourcePatternTests.xml @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/nonMatchingResourcePatternTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/nonMatchingResourcePatternTests.xml new file mode 100644 index 00000000000..7b04ea08c25 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/nonMatchingResourcePatternTests.xml @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyDefaultTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyDefaultTests.xml new file mode 100644 index 00000000000..ace6a278185 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyDefaultTests.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyInterfacesTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyInterfacesTests.xml new file mode 100644 index 00000000000..2d0d3b4a0d6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyInterfacesTests.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyInvalidConfigTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyInvalidConfigTests.xml new file mode 100644 index 00000000000..5dd54e68e96 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyInvalidConfigTests.xml @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyNoTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyNoTests.xml new file mode 100644 index 00000000000..e21696c0dee --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyNoTests.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyTargetClassTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyTargetClassTests.xml new file mode 100644 index 00000000000..421ab16720c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/scopedProxyTargetClassTests.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/simpleConfigTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/simpleConfigTests.xml new file mode 100644 index 00000000000..fe957429632 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/simpleConfigTests.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/simpleScanTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/simpleScanTests.xml new file mode 100644 index 00000000000..5431846bf5d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation/simpleScanTests.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation2/NamedStubDao2.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation2/NamedStubDao2.java new file mode 100644 index 00000000000..62ea7ee427e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation2/NamedStubDao2.java @@ -0,0 +1,31 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation2; + +import org.springframework.stereotype.Repository; + +/** + * @author Juergen Hoeller + */ +@Repository("myNamedDao") +public class NamedStubDao2 { + + public String find(int id) { + return "bar"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/annotation3/StubFooDao.java b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation3/StubFooDao.java new file mode 100644 index 00000000000..c1403e0e072 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/annotation3/StubFooDao.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation3; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Repository; +import org.springframework.context.annotation.FooDao; + +/** + * @author Mark Fisher + */ +@Repository +@Qualifier("testing") +public class StubFooDao implements FooDao { + + public String findFoo(int id) { + return "bar"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/AbstractGenericsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/AbstractGenericsTests.java new file mode 100644 index 00000000000..ce3209338cb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/AbstractGenericsTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2006 the original author 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; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; + +import junit.framework.TestCase; + +/** + * @author Serge Bogatyrjov + */ +public abstract class AbstractGenericsTests extends TestCase { + + protected Class targetClass; + + protected String methods[]; + + protected Type expectedResults[]; + + protected void executeTest() throws NoSuchMethodException { + String methodName = getName().substring(4); + methodName = methodName.substring(0, 1).toLowerCase() + methodName.substring(1); + for (int i = 0; i < this.methods.length; i++) { + if (methodName.equals(this.methods[i])) { + Method method = this.targetClass.getMethod(methodName); + Type type = getType(method); + assertEquals(this.expectedResults[i], type); + return; + } + } + throw new IllegalStateException("Bad test data"); + } + + protected abstract Type getType(Method method); + +} + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/BridgeMethodResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/BridgeMethodResolverTests.java new file mode 100644 index 00000000000..b3e9152a239 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/BridgeMethodResolverTests.java @@ -0,0 +1,1264 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.TypeVariable; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Delayed; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.orm.hibernate3.support.HibernateDaoSupport; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class BridgeMethodResolverTests extends TestCase { + + private static TypeVariable findTypeVariable(Class clazz, String name) { + TypeVariable[] variables = clazz.getTypeParameters(); + for (int i = 0; i < variables.length; i++) { + TypeVariable variable = variables[i]; + if (variable.getName().equals(name)) { + return variable; + } + } + return null; + } + + private static Method findMethodWithReturnType(String name, Class returnType, Class targetType) { + Method[] methods = targetType.getMethods(); + for (Method m : methods) { + if (m.getName().equals(name) && m.getReturnType().equals(returnType)) { + return m; + } + } + return null; + } + + + public void testFindBridgedMethod() throws Exception { + Method unbridged = MyFoo.class.getDeclaredMethod("someMethod", String.class, Object.class); + Method bridged = MyFoo.class.getDeclaredMethod("someMethod", Serializable.class, Object.class); + assertFalse(unbridged.isBridge()); + assertTrue(bridged.isBridge()); + + assertEquals("Unbridged method not returned directly", unbridged, BridgeMethodResolver.findBridgedMethod(unbridged)); + assertEquals("Incorrect bridged method returned", unbridged, BridgeMethodResolver.findBridgedMethod(bridged)); + } + + public void testFindBridgedVarargMethod() throws Exception { + Method unbridged = MyFoo.class.getDeclaredMethod("someVarargMethod", String.class, Object[].class); + Method bridged = MyFoo.class.getDeclaredMethod("someVarargMethod", Serializable.class, Object[].class); + assertFalse(unbridged.isBridge()); + assertTrue(bridged.isBridge()); + + assertEquals("Unbridged method not returned directly", unbridged, BridgeMethodResolver.findBridgedMethod(unbridged)); + assertEquals("Incorrect bridged method returned", unbridged, BridgeMethodResolver.findBridgedMethod(bridged)); + } + + public void testFindBridgedMethodInHierarchy() throws Exception { + Method unbridged = DateAdder.class.getMethod("add", Date.class); + Method bridged = DateAdder.class.getMethod("add", Object.class); + assertFalse(unbridged.isBridge()); + assertTrue(bridged.isBridge()); + + assertEquals("Unbridged method not returned directly", unbridged, BridgeMethodResolver.findBridgedMethod(unbridged)); + assertEquals("Incorrect bridged method returned", unbridged, BridgeMethodResolver.findBridgedMethod(bridged)); + } + + public void testIsBridgeMethodFor() throws Exception { + Map typeParameterMap = GenericTypeResolver.getTypeVariableMap(MyBar.class); + Method bridged = MyBar.class.getDeclaredMethod("someMethod", String.class, Object.class); + Method other = MyBar.class.getDeclaredMethod("someMethod", Integer.class, Object.class); + Method bridge = MyBar.class.getDeclaredMethod("someMethod", Object.class, Object.class); + + assertTrue("Should be bridge method", BridgeMethodResolver.isBridgeMethodFor(bridge, bridged, typeParameterMap)); + assertFalse("Should not be bridge method", BridgeMethodResolver.isBridgeMethodFor(bridge, other, typeParameterMap)); + } + + public void testCreateTypeVariableMap() throws Exception { + Map typeVariableMap = GenericTypeResolver.getTypeVariableMap(MyBar.class); + TypeVariable barT = findTypeVariable(InterBar.class, "T"); + assertEquals(String.class, typeVariableMap.get(barT)); + + typeVariableMap = GenericTypeResolver.getTypeVariableMap(MyFoo.class); + TypeVariable fooT = findTypeVariable(Foo.class, "T"); + assertEquals(String.class, typeVariableMap.get(fooT)); + + typeVariableMap = GenericTypeResolver.getTypeVariableMap(ExtendsEnclosing.ExtendsEnclosed.ExtendsReallyDeepNow.class); + TypeVariable r = findTypeVariable(Enclosing.Enclosed.ReallyDeepNow.class, "R"); + TypeVariable s = findTypeVariable(Enclosing.Enclosed.class, "S"); + TypeVariable t = findTypeVariable(Enclosing.class, "T"); + assertEquals(Long.class, typeVariableMap.get(r)); + assertEquals(Integer.class, typeVariableMap.get(s)); + assertEquals(String.class, typeVariableMap.get(t)); + } + + public void testDoubleParameterization() throws Exception { + Method objectBridge = MyBoo.class.getDeclaredMethod("foo", Object.class); + Method serializableBridge = MyBoo.class.getDeclaredMethod("foo", Serializable.class); + + Method stringFoo = MyBoo.class.getDeclaredMethod("foo", String.class); + Method integerFoo = MyBoo.class.getDeclaredMethod("foo", Integer.class); + + assertEquals("foo(String) not resolved.", stringFoo, BridgeMethodResolver.findBridgedMethod(objectBridge)); + assertEquals("foo(Integer) not resolved.", integerFoo, BridgeMethodResolver.findBridgedMethod(serializableBridge)); + } + + public void testFindBridgedMethodFromMultipleBridges() throws Exception { + Method loadWithObjectReturn = findMethodWithReturnType("load", Object.class, SettingsDaoImpl.class); + assertNotNull(loadWithObjectReturn); + + Method loadWithSettingsReturn = findMethodWithReturnType("load", Settings.class, SettingsDaoImpl.class); + assertNotNull(loadWithSettingsReturn); + + assertNotSame(loadWithObjectReturn, loadWithSettingsReturn); + + Method method = SettingsDaoImpl.class.getMethod("load"); + assertNotNull(method); + + assertEquals(method, BridgeMethodResolver.findBridgedMethod(loadWithObjectReturn)); + assertEquals(method, BridgeMethodResolver.findBridgedMethod(loadWithSettingsReturn)); + } + + public void testFindBridgedMethodFromParent() throws Exception { + Method loadFromParentBridge = SettingsDaoImpl.class.getMethod("loadFromParent"); + assertNotNull(loadFromParentBridge); + assertTrue(loadFromParentBridge.isBridge()); + + Method loadFromParent = AbstractDaoImpl.class.getMethod("loadFromParent"); + assertNotNull(loadFromParent); + assertFalse(loadFromParent.isBridge()); + + assertEquals(loadFromParent, BridgeMethodResolver.findBridgedMethod(loadFromParentBridge)); + } + + public void testWithSingleBoundParameterizedOnInstantiate() throws Exception { + Method bridgeMethod = DelayQueue.class.getMethod("add", Object.class); + assertTrue(bridgeMethod.isBridge()); + Method actualMethod = DelayQueue.class.getMethod("add", Delayed.class); + assertFalse(actualMethod.isBridge()); + assertEquals(actualMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + public void testWithDoubleBoundParameterizedOnInstantiate() throws Exception { + Method bridgeMethod = SerializableBounded.class.getMethod("boundedOperation", Object.class); + assertTrue(bridgeMethod.isBridge()); + Method actualMethod = SerializableBounded.class.getMethod("boundedOperation", HashMap.class); + assertFalse(actualMethod.isBridge()); + assertEquals(actualMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + public void testWithGenericParameter() throws Exception { + Method[] methods = StringGenericParameter.class.getMethods(); + Method bridgeMethod = null; + Method bridgedMethod = null; + for (int i = 0; i < methods.length; i++) { + Method method = methods[i]; + if ("getFor".equals(method.getName()) && !method.getParameterTypes()[0].equals(Integer.class)) { + if (method.getReturnType().equals(Object.class)) { + bridgeMethod = method; + } + else { + bridgedMethod = method; + } + } + } + assertNotNull("bridgedMethod should not be null", bridgedMethod); + assertNotNull("bridgeMethod should not be null", bridgeMethod); + assertTrue(bridgeMethod.isBridge()); + assertFalse(bridgedMethod.isBridge()); + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + public void testOnAllMethods() throws Exception { + Method[] methods = StringList.class.getMethods(); + for (int i = 0; i < methods.length; i++) { + Method method = methods[i]; + assertNotNull(BridgeMethodResolver.findBridgedMethod(method)); + } + } + + public void testSPR2583() throws Exception { + Method bridgedMethod = MessageBroadcasterImpl.class.getMethod("receive", MessageEvent.class); + assertFalse(bridgedMethod.isBridge()); + Method bridgeMethod = MessageBroadcasterImpl.class.getMethod("receive", Event.class); + assertTrue(bridgeMethod.isBridge()); + + Method otherMethod = MessageBroadcasterImpl.class.getMethod("receive", NewMessageEvent.class); + assertFalse(otherMethod.isBridge()); + + Map typeVariableMap = GenericTypeResolver.getTypeVariableMap(MessageBroadcasterImpl.class); + assertFalse("Match identified incorrectly", BridgeMethodResolver.isBridgeMethodFor(bridgeMethod, otherMethod, typeVariableMap)); + assertTrue("Match not found correctly", BridgeMethodResolver.isBridgeMethodFor(bridgeMethod, bridgedMethod, typeVariableMap)); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + public void testSPR2454() throws Exception { + Map typeVariableMap = GenericTypeResolver.getTypeVariableMap(YourHomer.class); + TypeVariable variable = findTypeVariable(MyHomer.class, "L"); + assertEquals(AbstractBounded.class, ((ParameterizedType) typeVariableMap.get(variable)).getRawType()); + } + + public void testSPR2603() throws Exception { + Method objectBridge = YourHomer.class.getDeclaredMethod("foo", Bounded.class); + Method abstractBoundedFoo = YourHomer.class.getDeclaredMethod("foo", AbstractBounded.class); + + Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(objectBridge); + assertEquals("foo(AbstractBounded) not resolved.", abstractBoundedFoo, bridgedMethod); + } + + public void testSPR2648() throws Exception { + Method bridgeMethod = GenericSqlMapIntegerDao.class.getDeclaredMethod("saveOrUpdate", Object.class); + assertTrue(bridgeMethod.isBridge()); + + Method bridgedMethod = GenericSqlMapIntegerDao.class.getDeclaredMethod("saveOrUpdate", Integer.class); + assertFalse(bridgedMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + public void testSPR2763() throws Exception { + Method bridgedMethod = AbstractDao.class.getDeclaredMethod("save", Object.class); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = UserDaoImpl.class.getDeclaredMethod("save", User.class); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + public void testSPR3041() throws Exception { + Method bridgedMethod = BusinessDao.class.getDeclaredMethod("save", Business.class); + assertNotNull(bridgedMethod); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = BusinessDao.class.getDeclaredMethod("save", Object.class); + assertNotNull(bridgeMethod); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + public void testSPR3173() throws Exception { + Method bridgedMethod = UserDaoImpl.class.getDeclaredMethod("saveVararg", User.class, Object[].class); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = UserDaoImpl.class.getDeclaredMethod("saveVararg", Object.class, Object[].class); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + public void testSPR3304() throws Exception { + Method bridgedMethod = MegaMessageProducerImpl.class.getDeclaredMethod("receive", MegaMessageEvent.class); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = MegaMessageProducerImpl.class.getDeclaredMethod("receive", MegaEvent.class); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + public void testSPR3324() throws Exception { + Method bridgedMethod = BusinessDao.class.getDeclaredMethod("get", Long.class); + assertNotNull(bridgedMethod); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = BusinessDao.class.getDeclaredMethod("get", Object.class); + assertNotNull(bridgeMethod); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + public void testSPR3357() throws Exception { + Method bridgedMethod = ExtendsAbstractImplementsInterface.class.getDeclaredMethod( + "doSomething", DomainObjectExtendsSuper.class, Object.class); + assertNotNull(bridgedMethod); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = ExtendsAbstractImplementsInterface.class.getDeclaredMethod( + "doSomething", DomainObjectSuper.class, Object.class); + assertNotNull(bridgeMethod); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + public void testSPR3485() throws Exception { + Method bridgedMethod = DomainObject.class.getDeclaredMethod( + "method2", ParameterType.class, byte[].class); + assertNotNull(bridgedMethod); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = DomainObject.class.getDeclaredMethod( + "method2", Serializable.class, Object.class); + assertNotNull(bridgeMethod); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + public void testSPR3534() throws Exception { + Method bridgedMethod = TestEmailProvider.class.getDeclaredMethod( + "findBy", EmailSearchConditions.class); + assertNotNull(bridgedMethod); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = TestEmailProvider.class.getDeclaredMethod( + "findBy", Object.class); + assertNotNull(bridgeMethod); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + + public static interface Foo { + + void someMethod(T theArg, Object otherArg); + + void someVarargMethod(T theArg, Object... otherArg); + } + + + public static class MyFoo implements Foo { + + public void someMethod(Integer theArg, Object otherArg) { + } + + public void someMethod(String theArg, Object otherArg) { + } + + public void someVarargMethod(String theArg, Object... otherArgs) { + } + } + + + public static abstract class Bar { + + void someMethod(Map m, Object otherArg) { + } + + void someMethod(T theArg, Map m) { + } + + abstract void someMethod(T theArg, Object otherArg); + } + + + public static abstract class InterBar extends Bar { + + } + + + public static class MyBar extends InterBar { + + public void someMethod(String theArg, Object otherArg) { + } + + public void someMethod(Integer theArg, Object otherArg) { + } + } + + + public interface Adder { + + void add(T item); + } + + + public abstract class AbstractDateAdder implements Adder { + + public abstract void add(Date date); + } + + + public class DateAdder extends AbstractDateAdder { + + @Override + public void add(Date date) { + } + } + + + public class Enclosing { + + public class Enclosed { + + public class ReallyDeepNow { + + void someMethod(S s, T t, R r) { + } + } + } + } + + + public class ExtendsEnclosing extends Enclosing { + + public class ExtendsEnclosed extends Enclosed { + + public class ExtendsReallyDeepNow extends ReallyDeepNow { + + void someMethod(Integer s, String t, Long r) { + throw new UnsupportedOperationException(); + } + } + } + } + + + public interface Boo { + + void foo(E e); + + void foo(T t); + } + + + public class MyBoo implements Boo { + + public void foo(String e) { + throw new UnsupportedOperationException(); + } + + public void foo(Integer t) { + throw new UnsupportedOperationException(); + } + } + + + interface Settings { + + } + + + interface ConcreteSettings extends Settings { + + } + + + interface Dao { + + T load(); + + S loadFromParent(); + } + + + interface SettingsDao extends Dao { + + T load(); + } + + + interface ConcreteSettingsDao extends SettingsDao { + + String loadFromParent(); + } + + + abstract class AbstractDaoImpl implements Dao { + + protected T object; + + protected S otherObject; + + protected AbstractDaoImpl(T object, S otherObject) { + this.object = object; + this.otherObject = otherObject; + } + + @Transactional(readOnly = true) + public S loadFromParent() { + return otherObject; + } + } + + + class SettingsDaoImpl extends AbstractDaoImpl implements ConcreteSettingsDao { + + protected SettingsDaoImpl(ConcreteSettings object) { + super(object, "From Parent"); + } + + @Transactional(readOnly = true) + public ConcreteSettings load() { + return super.object; + } + } + + + private static interface Bounded { + + boolean boundedOperation(E e); + } + + + private static class AbstractBounded implements Bounded { + + public boolean boundedOperation(E myE) { + return true; + } + } + + + private static class SerializableBounded extends AbstractBounded { + + public boolean boundedOperation(E myE) { + return false; + } + } + + + private static interface GenericParameter { + + T getFor(Class cls); + } + + + private static class StringGenericParameter implements GenericParameter { + + public String getFor(Class cls) { + return "foo"; + } + + public String getFor(Integer integer) { + return "foo"; + } + } + + + private static class StringList implements List { + + public int size() { + throw new UnsupportedOperationException(); + } + + public boolean isEmpty() { + throw new UnsupportedOperationException(); + } + + public boolean contains(Object o) { + throw new UnsupportedOperationException(); + } + + public Iterator iterator() { + throw new UnsupportedOperationException(); + } + + public Object[] toArray() { + throw new UnsupportedOperationException(); + } + + public T[] toArray(T[] a) { + throw new UnsupportedOperationException(); + } + + public boolean add(String o) { + throw new UnsupportedOperationException(); + } + + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + + public boolean containsAll(Collection c) { + throw new UnsupportedOperationException(); + } + + public boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + + public boolean addAll(int index, Collection c) { + throw new UnsupportedOperationException(); + } + + public boolean removeAll(Collection c) { + throw new UnsupportedOperationException(); + } + + public boolean retainAll(Collection c) { + throw new UnsupportedOperationException(); + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public String get(int index) { + throw new UnsupportedOperationException(); + } + + public String set(int index, String element) { + throw new UnsupportedOperationException(); + } + + public void add(int index, String element) { + throw new UnsupportedOperationException(); + } + + public String remove(int index) { + throw new UnsupportedOperationException(); + } + + public int indexOf(Object o) { + throw new UnsupportedOperationException(); + } + + public int lastIndexOf(Object o) { + throw new UnsupportedOperationException(); + } + + public ListIterator listIterator() { + throw new UnsupportedOperationException(); + } + + public ListIterator listIterator(int index) { + throw new UnsupportedOperationException(); + } + + public List subList(int fromIndex, int toIndex) { + throw new UnsupportedOperationException(); + } + } + + + public interface Event { + + int getPriority(); + } + + + public class GenericEvent implements Event { + + private int priority; + + public int getPriority() { + return priority; + } + + /** + * Constructor that takes an event priority + */ + public GenericEvent(int priority) { + this.priority = priority; + } + + /** + * Default Constructor + */ + public GenericEvent() { + } + } + + + public interface UserInitiatedEvent { + + //public Session getInitiatorSession(); + } + + + public abstract class BaseUserInitiatedEvent extends GenericEvent implements UserInitiatedEvent { + + } + + + public class MessageEvent extends BaseUserInitiatedEvent { + + } + + + public interface Channel { + + void send(E event); + + void subscribe(final Receiver receiver, Class event); + + void unsubscribe(final Receiver receiver, Class event); + } + + + public interface Broadcaster { + + } + + + public interface EventBroadcaster extends Broadcaster { + + public void subscribe(); + + public void unsubscribe(); + + public void setChannel(Channel channel); + } + + + public class GenericBroadcasterImpl implements Broadcaster { + + } + + + public abstract class GenericEventBroadcasterImpl extends GenericBroadcasterImpl + implements EventBroadcaster, BeanNameAware { + + private Class[] subscribingEvents; + + private Channel channel; + + /** + * Abstract method to retrieve instance of subclass + * + * @return receiver instance + */ + public abstract Receiver getInstance(); + + public void setChannel(Channel channel) { + this.channel = channel; + } + + private String beanName; + + public void setBeanName(String name) { + this.beanName = name; + } + + public void subscribe() { + + } + + public void unsubscribe() { + + } + + public GenericEventBroadcasterImpl(Class... events) { + + } + } + + + public interface Receiver { + + void receive(E event); + } + + + public interface MessageBroadcaster extends Receiver { + + } + + + public class RemovedMessageEvent extends MessageEvent { + + } + + + public class NewMessageEvent extends MessageEvent { + + } + + + public class ModifiedMessageEvent extends MessageEvent { + + } + + + public class MessageBroadcasterImpl extends GenericEventBroadcasterImpl + implements MessageBroadcaster { + + public MessageBroadcasterImpl() { + super(NewMessageEvent.class); + } + + public void receive(MessageEvent event) { + throw new UnsupportedOperationException("should not be called, use subclassed events"); + } + + public void receive(NewMessageEvent event) { + } + + @Override + public Receiver getInstance() { + return null; + } + + public void receive(RemovedMessageEvent event) { + } + + public void receive(ModifiedMessageEvent event) { + } + } + + + //----------------------------- + // SPR-2454 Test Classes + //----------------------------- + + public interface SimpleGenericRepository { + + public Class getPersistentClass(); + + + List findByQuery(); + + + List findAll(); + + + T refresh(T entity); + + + T saveOrUpdate(T entity); + + + void delete(Collection entities); + } + + + public interface RepositoryRegistry { + + SimpleGenericRepository getFor(Class entityType); + } + + + public class SettableRepositoryRegistry> + implements RepositoryRegistry, InitializingBean { + + protected void injectInto(R rep) { + } + + public void register(R rep) { + } + + public void register(R... reps) { + } + + public void setRepos(R... reps) { + } + + public SimpleGenericRepository getFor(Class entityType) { + return null; + } + + public void afterPropertiesSet() throws Exception { + } + } + + + public interface ConvenientGenericRepository extends SimpleGenericRepository { + + T findById(ID id, boolean lock); + + List findByExample(T exampleInstance); + + void delete(ID id); + + void delete(T entity); + } + + + public class GenericHibernateRepository extends HibernateDaoSupport + implements ConvenientGenericRepository { + + /** + * @param c Mandatory. The domain class this repository is responsible for. + */ + // Since it is impossible to determine the actual type of a type + // parameter (!), we resort to requiring the caller to provide the + // actual type as parameter, too. + // Not set in a constructor to enable easy CGLIB-proxying (passing + // constructor arguments to Spring AOP proxies is quite cumbersome). + public void setPersistentClass(Class c) { + } + + public Class getPersistentClass() { + return null; + } + + public T findById(ID id, boolean lock) { + return null; + } + + public List findAll() { + return null; + } + + public List findByExample(T exampleInstance) { + return null; + } + + public List findByQuery() { + return null; + } + + public T saveOrUpdate(T entity) { + return null; + } + + public void delete(T entity) { + } + + public T refresh(T entity) { + return null; + } + + public void delete(ID id) { + } + + public void delete(Collection entities) { + } + } + + + public class HibernateRepositoryRegistry extends SettableRepositoryRegistry> { + + public void injectInto(GenericHibernateRepository rep) { + } + + public GenericHibernateRepository getFor(Class entityType) { + return null; + } + } + + + //------------------- + // SPR-2603 classes + //------------------- + + public interface Homer { + + void foo(E e); + } + + + public class MyHomer, L extends T> implements Homer { + + public void foo(L t) { + throw new UnsupportedOperationException(); + } + } + + + public class YourHomer, L extends T> extends MyHomer { + + public void foo(L t) { + throw new UnsupportedOperationException(); + } + } + + + public interface GenericDao { + + public void saveOrUpdate(T t); + } + + + public interface ConvenienceGenericDao extends GenericDao { + } + + + public class GenericSqlMapDao implements ConvenienceGenericDao { + + public void saveOrUpdate(T t) { + throw new UnsupportedOperationException(); + } + } + + + public class GenericSqlMapIntegerDao extends GenericSqlMapDao { + + public void saveOrUpdate(T t) { + } + } + + + public class Permission { + } + + + public class User { + } + + + public interface UserDao { + + @Transactional + void save(User user); + + @Transactional + void save(Permission perm); + } + + + public abstract class AbstractDao { + + public void save(T t) { + } + + public void saveVararg(T t, Object... args) { + } + } + + + public class UserDaoImpl extends AbstractDao implements UserDao { + + public void save(Permission perm) { + } + + public void saveVararg(User user, Object... args) { + } + } + + + public interface DaoInterface { + T get(P id); + } + + + public abstract class BusinessGenericDao implements DaoInterface { + + public void save(T object) { + } + } + + + public class Business { + + } + + + public class BusinessDao extends BusinessGenericDao, Long> { + + public void save(Business business) { + } + + public Business get(Long id) { + return null; + } + + public Business get(String code) { + return null; + } + } + + + //------------------- + // SPR-3304 classes + //------------------- + + private static class MegaEvent { + + } + + + private static class MegaMessageEvent extends MegaEvent { + + } + + + private static class NewMegaMessageEvent extends MegaEvent { + + } + + + private static class ModifiedMegaMessageEvent extends MegaEvent { + + } + + + private static interface MegaReceiver { + + void receive(E event); + } + + + private static interface MegaMessageProducer extends MegaReceiver { + + } + + + private static class Other { + + } + + + private static class MegaMessageProducerImpl extends Other implements MegaMessageProducer { + + public void receive(NewMegaMessageEvent event) { + throw new UnsupportedOperationException(); + } + + public void receive(ModifiedMegaMessageEvent event) { + throw new UnsupportedOperationException(); + } + + public void receive(MegaMessageEvent event) { + throw new UnsupportedOperationException(); + } + } + + + //------------------- + // SPR-3357 classes + //------------------- + + private static class DomainObjectSuper { + + } + + + private static class DomainObjectExtendsSuper extends DomainObjectSuper { + + } + + + private interface IGenericInterface { + + void doSomething(final D domainObject, final T value); + } + + + private static abstract class AbstractImplementsInterface implements IGenericInterface { + + public void doSomething(D domainObject, T value) { + } + + public void anotherBaseMethod() { + } + } + + + private static class ExtendsAbstractImplementsInterface extends AbstractImplementsInterface { + + @Override + public void doSomething(DomainObjectExtendsSuper domainObject, T value) { + super.doSomething(domainObject, value); + } + } + + + //------------------- + // SPR-3485 classes + //------------------- + + private static class ParameterType implements Serializable { + + } + + + private static class AbstractDomainObject

{ + + public R method1(P p) { + return null; + } + + public void method2(P p, R r) { + } + } + + + private static class DomainObject extends AbstractDomainObject { + + public byte[] method1(ParameterType p) { + return super.method1(p); + } + + public void method2(ParameterType p, byte[] r) { + super.method2(p, r); + } + } + + + //------------------- + // SPR-3534 classes + //------------------- + + public interface SearchProvider { + + Collection findBy(CONDITIONS_TYPE conditions); + } + + + public static class SearchConditions { + + } + + + public interface IExternalMessageProvider + extends SearchProvider { + } + + + public static class ExternalMessage { + + } + + + public static class ExternalMessageSearchConditions extends SearchConditions { + + } + + + public static class ExternalMessageProvider> + implements IExternalMessageProvider { + + public Collection findBy(T conditions) { + return null; + } + } + + + public static class EmailMessage extends ExternalMessage { + + } + + + public static class EmailSearchConditions extends ExternalMessageSearchConditions { + + } + + + public static class EmailMessageProvider extends ExternalMessageProvider { } + + + public static class TestEmailProvider extends EmailMessageProvider { + + public Collection findBy(EmailSearchConditions conditions) { + return null; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/GenericCollectionTypeResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/GenericCollectionTypeResolverTests.java new file mode 100644 index 00000000000..f830eb4ea4e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/GenericCollectionTypeResolverTests.java @@ -0,0 +1,136 @@ +/* + * Copyright 2002-2006 the original author 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; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.AbstractMap; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.springframework.beans.GenericBean; +import org.springframework.core.io.Resource; + +/** + * @author Serge Bogatyrjov + * @author Juergen Hoeller + */ +public class GenericCollectionTypeResolverTests extends AbstractGenericsTests { + + protected void setUp() throws Exception { + this.targetClass = Foo.class; + this.methods = new String[] {"a", "b", "b2", "b3", "c", "d", "d2", "d3", "e", "e2", "e3"}; + this.expectedResults = new Class[] { + Integer.class, null, null, Set.class, null, Integer.class, + Integer.class, Integer.class, Integer.class, Integer.class, Integer.class}; + } + + protected Type getType(Method method) { + return GenericCollectionTypeResolver.getMapValueReturnType(method); + } + + public void testA() throws Exception { + executeTest(); + } + + public void testB() throws Exception { + executeTest(); + } + + public void testB2() throws Exception { + executeTest(); + } + + public void testB3() throws Exception { + executeTest(); + } + + public void testC() throws Exception { + executeTest(); + } + + public void testD() throws Exception { + executeTest(); + } + + public void testD2() throws Exception { + executeTest(); + } + + public void testD3() throws Exception { + executeTest(); + } + + public void testE() throws Exception { + executeTest(); + } + + public void testE2() throws Exception { + executeTest(); + } + + public void testE3() throws Exception { + executeTest(); + } + + public void testProgrammaticListIntrospection() throws Exception { + Method setter = GenericBean.class.getMethod("setResourceList", List.class); + assertEquals(Resource.class, + GenericCollectionTypeResolver.getCollectionParameterType(new MethodParameter(setter, 0))); + + Method getter = GenericBean.class.getMethod("getResourceList"); + assertEquals(Resource.class, + GenericCollectionTypeResolver.getCollectionReturnType(getter)); + } + + + private abstract class CustomMap extends AbstractMap { + } + + + private abstract class OtherCustomMap implements Map { + } + + + private interface Foo { + + Map a(); + + Map b(); + + Map b2(); + + Map b3(); + + Map c(); + + CustomMap d(); + + CustomMap d2(); + + CustomMap d3(); + + OtherCustomMap e(); + + OtherCustomMap e2(); + + OtherCustomMap e3(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java new file mode 100644 index 00000000000..348bea9833a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java @@ -0,0 +1,279 @@ +/* + * Copyright 2002-2006 the original author 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.annotation; + +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; +import static org.springframework.core.annotation.AnnotationUtils.findAnnotationDeclaringClass; +import static org.springframework.core.annotation.AnnotationUtils.getAnnotation; +import static org.springframework.core.annotation.AnnotationUtils.isAnnotationDeclaredLocally; +import static org.springframework.core.annotation.AnnotationUtils.isAnnotationInherited; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.springframework.core.Ordered; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Sam Brannen + */ +public class AnnotationUtilsTests extends TestCase { + + public void testFindMethodAnnotationOnLeaf() throws SecurityException, NoSuchMethodException { + + final Method m = Leaf.class.getMethod("annotatedOnLeaf", (Class[]) null); + assertNotNull(m.getAnnotation(Order.class)); + assertNotNull(getAnnotation(m, Order.class)); + assertNotNull(findAnnotation(m, Order.class)); + } + + public void testFindMethodAnnotationOnRoot() throws SecurityException, NoSuchMethodException { + + final Method m = Leaf.class.getMethod("annotatedOnRoot", (Class[]) null); + assertNotNull(m.getAnnotation(Order.class)); + assertNotNull(getAnnotation(m, Order.class)); + assertNotNull(findAnnotation(m, Order.class)); + } + + public void testFindMethodAnnotationOnRootButOverridden() throws SecurityException, NoSuchMethodException { + + final Method m = Leaf.class.getMethod("overrideWithoutNewAnnotation", (Class[]) null); + assertNull(m.getAnnotation(Order.class)); + assertNull(getAnnotation(m, Order.class)); + assertNotNull(findAnnotation(m, Order.class)); + } + + public void testFindMethodAnnotationNotAnnotated() throws SecurityException, NoSuchMethodException { + + final Method m = Leaf.class.getMethod("notAnnotated", (Class[]) null); + assertNull(findAnnotation(m, Order.class)); + } + + public void testFindMethodAnnotationOnBridgeMethod() throws Exception { + + final Method m = SimpleFoo.class.getMethod("something", Object.class); + assertTrue(m.isBridge()); + assertNull(m.getAnnotation(Order.class)); + assertNull(getAnnotation(m, Order.class)); + assertNotNull(findAnnotation(m, Order.class)); + assertNull(m.getAnnotation(Transactional.class)); + assertNotNull(getAnnotation(m, Transactional.class)); + assertNotNull(findAnnotation(m, Transactional.class)); + } + + // TODO consider whether we want this to handle annotations on interfaces + // public void testFindMethodAnnotationFromInterfaceImplementedByRoot() + // throws Exception { + // Method m = Leaf.class.getMethod("fromInterfaceImplementedByRoot", + // (Class[]) null); + // Order o = findAnnotation(Order.class, m, Leaf.class); + // assertNotNull(o); + // } + + public void testFindAnnotationDeclaringClass() throws Exception { + + // no class-level annotation + assertNull(findAnnotationDeclaringClass(Transactional.class, NonAnnotatedInterface.class)); + assertNull(findAnnotationDeclaringClass(Transactional.class, NonAnnotatedClass.class)); + + // inherited class-level annotation; note: @Transactional is inherited + assertEquals(InheritedAnnotationInterface.class, findAnnotationDeclaringClass(Transactional.class, + InheritedAnnotationInterface.class)); + assertNull(findAnnotationDeclaringClass(Transactional.class, SubInheritedAnnotationInterface.class)); + assertEquals(InheritedAnnotationClass.class, findAnnotationDeclaringClass(Transactional.class, + InheritedAnnotationClass.class)); + assertEquals(InheritedAnnotationClass.class, findAnnotationDeclaringClass(Transactional.class, + SubInheritedAnnotationClass.class)); + + // non-inherited class-level annotation; note: @Order is not inherited, + // but findAnnotationDeclaringClass() should still find it. + assertEquals(NonInheritedAnnotationInterface.class, findAnnotationDeclaringClass(Order.class, + NonInheritedAnnotationInterface.class)); + assertNull(findAnnotationDeclaringClass(Order.class, SubNonInheritedAnnotationInterface.class)); + assertEquals(NonInheritedAnnotationClass.class, findAnnotationDeclaringClass(Order.class, + NonInheritedAnnotationClass.class)); + assertEquals(NonInheritedAnnotationClass.class, findAnnotationDeclaringClass(Order.class, + SubNonInheritedAnnotationClass.class)); + } + + public void testIsAnnotationDeclaredLocally() throws Exception { + + // no class-level annotation + assertFalse(isAnnotationDeclaredLocally(Transactional.class, NonAnnotatedInterface.class)); + assertFalse(isAnnotationDeclaredLocally(Transactional.class, NonAnnotatedClass.class)); + + // inherited class-level annotation; note: @Transactional is inherited + assertTrue(isAnnotationDeclaredLocally(Transactional.class, InheritedAnnotationInterface.class)); + assertFalse(isAnnotationDeclaredLocally(Transactional.class, SubInheritedAnnotationInterface.class)); + assertTrue(isAnnotationDeclaredLocally(Transactional.class, InheritedAnnotationClass.class)); + assertFalse(isAnnotationDeclaredLocally(Transactional.class, SubInheritedAnnotationClass.class)); + + // non-inherited class-level annotation; note: @Order is not inherited + assertTrue(isAnnotationDeclaredLocally(Order.class, NonInheritedAnnotationInterface.class)); + assertFalse(isAnnotationDeclaredLocally(Order.class, SubNonInheritedAnnotationInterface.class)); + assertTrue(isAnnotationDeclaredLocally(Order.class, NonInheritedAnnotationClass.class)); + assertFalse(isAnnotationDeclaredLocally(Order.class, SubNonInheritedAnnotationClass.class)); + } + + public void testIsAnnotationInherited() throws Exception { + + // no class-level annotation + assertFalse(isAnnotationInherited(Transactional.class, NonAnnotatedInterface.class)); + assertFalse(isAnnotationInherited(Transactional.class, NonAnnotatedClass.class)); + + // inherited class-level annotation; note: @Transactional is inherited + assertFalse(isAnnotationInherited(Transactional.class, InheritedAnnotationInterface.class)); + // isAnnotationInherited() does not currently traverse interface + // hierarchies. Thus the following, though perhaps counter intuitive, + // must be false: + assertFalse(isAnnotationInherited(Transactional.class, SubInheritedAnnotationInterface.class)); + assertFalse(isAnnotationInherited(Transactional.class, InheritedAnnotationClass.class)); + assertTrue(isAnnotationInherited(Transactional.class, SubInheritedAnnotationClass.class)); + + // non-inherited class-level annotation; note: @Order is not inherited + assertFalse(isAnnotationInherited(Order.class, NonInheritedAnnotationInterface.class)); + assertFalse(isAnnotationInherited(Order.class, SubNonInheritedAnnotationInterface.class)); + assertFalse(isAnnotationInherited(Order.class, NonInheritedAnnotationClass.class)); + assertFalse(isAnnotationInherited(Order.class, SubNonInheritedAnnotationClass.class)); + } + + public void testGetValueFromAnnotation() throws Exception { + + final Method method = SimpleFoo.class.getMethod("something", Object.class); + final Order order = findAnnotation(method, Order.class); + + assertEquals(1, AnnotationUtils.getValue(order, AnnotationUtils.VALUE)); + assertEquals(1, AnnotationUtils.getValue(order)); + } + + public void testGetDefaultValueFromAnnotation() throws Exception { + + final Method method = SimpleFoo.class.getMethod("something", Object.class); + final Order order = findAnnotation(method, Order.class); + + assertEquals(Ordered.LOWEST_PRECEDENCE, AnnotationUtils.getDefaultValue(order, AnnotationUtils.VALUE)); + assertEquals(Ordered.LOWEST_PRECEDENCE, AnnotationUtils.getDefaultValue(order)); + } + + public void testGetDefaultValueFromAnnotationType() throws Exception { + + assertEquals(Ordered.LOWEST_PRECEDENCE, AnnotationUtils.getDefaultValue(Order.class, AnnotationUtils.VALUE)); + assertEquals(Ordered.LOWEST_PRECEDENCE, AnnotationUtils.getDefaultValue(Order.class)); + } + + public static interface AnnotatedInterface { + + @Order(0) + void fromInterfaceImplementedByRoot(); + } + + public static class Root implements AnnotatedInterface { + + @Order(27) + public void annotatedOnRoot() { + + } + + public void overrideToAnnotate() { + + } + + @Order(27) + public void overrideWithoutNewAnnotation() { + + } + + public void notAnnotated() { + + } + + public void fromInterfaceImplementedByRoot() { + + } + } + + public static class Leaf extends Root { + + @Order(25) + public void annotatedOnLeaf() { + + } + + @Override + @Order(1) + public void overrideToAnnotate() { + + } + + @Override + public void overrideWithoutNewAnnotation() { + + } + } + + public static abstract class Foo { + + @Order(1) + public abstract void something(T arg); + } + + public static class SimpleFoo extends Foo { + + @Transactional + public void something(final String arg) { + + } + } + + @Transactional + public static interface InheritedAnnotationInterface { + } + + public static interface SubInheritedAnnotationInterface extends InheritedAnnotationInterface { + } + + @Order + public static interface NonInheritedAnnotationInterface { + } + + public static interface SubNonInheritedAnnotationInterface extends NonInheritedAnnotationInterface { + } + + public static class NonAnnotatedClass { + } + + public static interface NonAnnotatedInterface { + } + + @Transactional + public static class InheritedAnnotationClass { + } + + public static class SubInheritedAnnotationClass extends InheritedAnnotationClass { + } + + @Order + public static class NonInheritedAnnotationClass { + } + + public static class SubNonInheritedAnnotationClass extends NonInheritedAnnotationClass { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java new file mode 100644 index 00000000000..b96aeea8547 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java @@ -0,0 +1,77 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.type; + +import java.io.IOException; +import java.io.Serializable; +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.context.annotation.Scope; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; +import org.springframework.stereotype.Component; + +/** + * @author Juergen Hoeller + */ +public class AnnotationMetadataTests extends TestCase { + + public void testStandardAnnotationMetadata() throws IOException { + StandardAnnotationMetadata annInfo = new StandardAnnotationMetadata(AnnotatedComponent.class); + doTestAnnotationInfo(annInfo); + } + + public void testAsmAnnotationMetadata() throws IOException { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotatedComponent.class.getName()); + doTestAnnotationInfo(metadataReader.getAnnotationMetadata()); + } + + private void doTestAnnotationInfo(AnnotationMetadata metadata) { + assertEquals(AnnotatedComponent.class.getName(), metadata.getClassName()); + assertFalse(metadata.isInterface()); + assertFalse(metadata.isAbstract()); + assertTrue(metadata.isConcrete()); + assertTrue(metadata.hasSuperClass()); + assertEquals(Object.class.getName(), metadata.getSuperClassName()); + assertEquals(1, metadata.getInterfaceNames().length); + assertEquals(Serializable.class.getName(), metadata.getInterfaceNames()[0]); + + assertTrue(metadata.hasAnnotation(Component.class.getName())); + assertTrue(metadata.hasAnnotation(Scope.class.getName())); + assertEquals(2, metadata.getAnnotationTypes().size()); + assertTrue(metadata.getAnnotationTypes().contains(Component.class.getName())); + assertTrue(metadata.getAnnotationTypes().contains(Scope.class.getName())); + + Map cattrs = metadata.getAnnotationAttributes(Component.class.getName()); + assertEquals(1, cattrs.size()); + assertEquals("myName", cattrs.get("value")); + Map sattrs = metadata.getAnnotationAttributes(Scope.class.getName()); + assertEquals(1, sattrs.size()); + assertEquals("myScope", sattrs.get("value")); + } + + + @Component("myName") + @Scope("myScope") + private static class AnnotatedComponent implements Serializable { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/type/AnnotationTypeFilterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/type/AnnotationTypeFilterTests.java new file mode 100644 index 00000000000..3d086d2bc33 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/type/AnnotationTypeFilterTests.java @@ -0,0 +1,130 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.type; + +import java.lang.annotation.Inherited; + +import junit.framework.TestCase; + +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.stereotype.Component; + +/** + * @author Ramnivas Laddad + * @author Juergen Hoeller + */ +public class AnnotationTypeFilterTests extends TestCase { + + public void testDirectAnnotationMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeComponent"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AnnotationTypeFilter filter = new AnnotationTypeFilter(InheritedAnnotation.class); + assertTrue(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + public void testInheritedAnnotationFromInterfaceDoesNotMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeSubClassOfSomeComponentInterface"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AnnotationTypeFilter filter = new AnnotationTypeFilter(InheritedAnnotation.class); + // Must fail as annotation on interfaces should not be considered a match + assertFalse(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + public void testInheritedAnnotationFromBaseClassDoesMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeSubClassOfSomeComponent"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AnnotationTypeFilter filter = new AnnotationTypeFilter(InheritedAnnotation.class); + assertTrue(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + public void testNonInheritedAnnotationDoesNotMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeSubclassOfSomeClassMarkedWithNonInheritedAnnotation"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AnnotationTypeFilter filter = new AnnotationTypeFilter(NonInheritedAnnotation.class); + // Must fail as annotation isn't inherited + assertFalse(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + public void testNonAnnotatedClassDoesntMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeNonCandidateClass"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AnnotationTypeFilter filter = new AnnotationTypeFilter(Component.class); + assertFalse(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + + // We must use a standalone set of types to ensure that no one else is loading them + // and interfering with ClassloadingAssertions.assertClassNotLoaded() + + @Inherited + private static @interface InheritedAnnotation { + } + + + @InheritedAnnotation + private static class SomeComponent { + } + + + @InheritedAnnotation + private static interface SomeComponentInterface { + } + + + private static class SomeSubClassOfSomeComponentInterface implements SomeComponentInterface { + } + + + private static class SomeSubClassOfSomeComponent extends SomeComponent { + } + + + private static @interface NonInheritedAnnotation { + } + + + @NonInheritedAnnotation + private static class SomeClassMarkedWithNonInheritedAnnotation { + } + + + private static class SomeSubclassOfSomeClassMarkedWithNonInheritedAnnotation extends SomeClassMarkedWithNonInheritedAnnotation { + } + + + private static class SomeNonCandidateClass { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/type/AspectJTypeFilterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/type/AspectJTypeFilterTests.java new file mode 100644 index 00000000000..e1cf0809d76 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/type/AspectJTypeFilterTests.java @@ -0,0 +1,164 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.type; + +import junit.framework.TestCase; + +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; +import org.springframework.core.type.filter.AspectJTypeFilter; +import org.springframework.stereotype.Component; + +/** + * @author Ramnivas Laddad + */ +public class AspectJTypeFilterTests extends TestCase { + + public void testNamePatternMatches() throws Exception { + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClass", + "org.springframework.core.type.AspectJTypeFilterTests.SomeClass"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClass", + "*"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClass", + "*..SomeClass"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClass", + "org..SomeClass"); + } + + public void testNamePatternNoMatches() throws Exception { + assertNoMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClass", + "org.springframework.core.type.AspectJTypeFilterTests.SomeClassX"); + } + + public void testSubclassPatternMatches() throws Exception { + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClass", + "org.springframework.core.type.AspectJTypeFilterTests.SomeClass+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClass", + "*+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClass", + "java.lang.Object+"); + + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassImplementingSomeInterface", + "org.springframework.core.type.AspectJTypeFilterTests.SomeInterface+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassImplementingSomeInterface", + "*+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassImplementingSomeInterface", + "java.lang.Object+"); + + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface", + "org.springframework.core.type.AspectJTypeFilterTests.SomeInterface+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface", + "org.springframework.core.type.AspectJTypeFilterTests.SomeClassExtendingSomeClass+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface", + "org.springframework.core.type.AspectJTypeFilterTests.SomeClass+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface", + "*+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface", + "java.lang.Object+"); + } + + public void testSubclassPatternNoMatches() throws Exception { + assertNoMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClass", + "java.lang.String+"); + } + + public void testAnnotationPatternMathces() throws Exception { + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassAnnotatedWithComponent", + "@org.springframework.stereotype.Component *..*"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassAnnotatedWithComponent", + "@* *..*"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassAnnotatedWithComponent", + "@*..* *..*"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassAnnotatedWithComponent", + "@*..*Component *..*"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassAnnotatedWithComponent", + "@org.springframework.stereotype.Component *..*Component"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassAnnotatedWithComponent", + "@org.springframework.stereotype.Component *"); + } + + public void testAnnotationPatternNoMathces() throws Exception { + assertNoMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassAnnotatedWithComponent", + "@org.springframework.stereotype.Repository *..*"); + } + + public void testCompositionPatternMatches() throws Exception { + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClass", + "!*..SomeOtherClass"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface", + "org.springframework.core.type.AspectJTypeFilterTests.SomeInterface+ " + + "&& org.springframework.core.type.AspectJTypeFilterTests.SomeClass+ " + + "&& org.springframework.core.type.AspectJTypeFilterTests.SomeClassExtendingSomeClass+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface", + "org.springframework.core.type.AspectJTypeFilterTests.SomeInterface+ " + + "|| org.springframework.core.type.AspectJTypeFilterTests.SomeClass+ " + + "|| org.springframework.core.type.AspectJTypeFilterTests.SomeClassExtendingSomeClass+"); + } + + public void testCompositionPatternNoMatches() throws Exception { + assertNoMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClass", + "*..Bogus && org.springframework.core.type.AspectJTypeFilterTests.SomeClass"); + } + + private void assertMatch(String type, String typePattern) throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(type); + + AspectJTypeFilter filter = new AspectJTypeFilter(typePattern, getClass().getClassLoader()); + assertTrue(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(type); + } + + private void assertNoMatch(String type, String typePattern) throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(type); + + AspectJTypeFilter filter = new AspectJTypeFilter(typePattern, getClass().getClassLoader()); + assertFalse(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(type); + } + + + // We must use a standalone set of types to ensure that no one else is loading them + // and interfering with ClassloadingAssertions.assertClassNotLoaded() + static interface SomeInterface { + } + + + static class SomeClass { + } + + + static class SomeClassExtendingSomeClass extends SomeClass { + } + + + static class SomeClassImplementingSomeInterface implements SomeInterface { + } + + + static class SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface + extends SomeClassExtendingSomeClass implements SomeInterface { + } + + + @Component + static class SomeClassAnnotatedWithComponent { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/type/AssignableTypeFilterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/type/AssignableTypeFilterTests.java new file mode 100644 index 00000000000..de76ddeae1e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/type/AssignableTypeFilterTests.java @@ -0,0 +1,97 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.type; + +import junit.framework.TestCase; + +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; +import org.springframework.core.type.filter.AssignableTypeFilter; +import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport; +import org.springframework.jdbc.core.support.JdbcDaoSupport; + +/** + * @author Ramnivas Laddad + * @author Juergen Hoeller + */ +public class AssignableTypeFilterTests extends TestCase { + + public void testDirectMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AssignableTypeFilterTests$TestNonInheritingClass"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AssignableTypeFilter matchingFilter = new AssignableTypeFilter(TestNonInheritingClass.class); + AssignableTypeFilter notMatchingFilter = new AssignableTypeFilter(TestInterface.class); + assertFalse(notMatchingFilter.match(metadataReader, metadataReaderFactory)); + assertTrue(matchingFilter.match(metadataReader, metadataReaderFactory)); + } + + public void testInterfaceMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AssignableTypeFilterTests$TestInterfaceImpl"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AssignableTypeFilter filter = new AssignableTypeFilter(TestInterface.class); + assertTrue(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + public void testSuperClassMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AssignableTypeFilterTests$SomeDaoLikeImpl"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AssignableTypeFilter filter = new AssignableTypeFilter(SimpleJdbcDaoSupport.class); + assertTrue(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + public void testInterfaceThroughSuperClassMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AssignableTypeFilterTests$SomeDaoLikeImpl"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AssignableTypeFilter filter = new AssignableTypeFilter(JdbcDaoSupport.class); + assertTrue(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + + // We must use a standalone set of types to ensure that no one else is loading them + // and interfere with ClassloadingAssertions.assertClassNotLoaded() + private static class TestNonInheritingClass { + } + + + private static interface TestInterface { + } + + + private static class TestInterfaceImpl implements TestInterface { + } + + + private static interface SomeDaoLikeInterface { + } + + + private static class SomeDaoLikeImpl extends SimpleJdbcDaoSupport implements SomeDaoLikeInterface { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/type/ClassloadingAssertions.java b/org.springframework.testsuite/src/test/java/org/springframework/core/type/ClassloadingAssertions.java new file mode 100644 index 00000000000..089c6858559 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/type/ClassloadingAssertions.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.core.type; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; + +/** + * + * @author Ramnivas Laddad + * + */ +public class ClassloadingAssertions { + public static boolean isClassLoaded(String className) { + ClassLoader cl = ClassUtils.getDefaultClassLoader(); + Method findLoadeClassMethod = ReflectionUtils.findMethod(cl.getClass(), "findLoadedClass", new Class[]{String.class}); + findLoadeClassMethod.setAccessible(true); + Class loadedClass = (Class)ReflectionUtils.invokeMethod(findLoadeClassMethod, cl, new Object[]{className}); + return loadedClass != null; + } + + public static void assertClassLoaded(String className) { + } + + public static void assertClassNotLoaded(String className) { + TestCase.assertFalse("Class shouldn't have been loaded", isClassLoaded(className)); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ejb/access/LocalSlsbInvokerInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/ejb/access/LocalSlsbInvokerInterceptorTests.java new file mode 100644 index 00000000000..2d3a52b69dd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ejb/access/LocalSlsbInvokerInterceptorTests.java @@ -0,0 +1,229 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ejb.access; + +import javax.ejb.CreateException; +import javax.ejb.EJBLocalHome; +import javax.ejb.EJBLocalObject; +import javax.naming.Context; +import javax.naming.NamingException; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.jndi.JndiTemplate; + +/** + * @author Rod Johnson + * @author Juergen Hoeller +*/ +public class LocalSlsbInvokerInterceptorTests extends TestCase { + + /** + * Test that it performs the correct lookup. + */ + public void testPerformsLookup() throws Exception { + MockControl ejbControl = MockControl.createControl(LocalInterfaceWithBusinessMethods.class); + final LocalInterfaceWithBusinessMethods ejb = (LocalInterfaceWithBusinessMethods) ejbControl.getMock(); + ejbControl.replay(); + + final String jndiName= "foobar"; + MockControl contextControl = contextControl(jndiName, ejb); + + LocalSlsbInvokerInterceptor si = configuredInterceptor(contextControl, jndiName); + + contextControl.verify(); + } + + public void testLookupFailure() throws Exception { + final NamingException nex = new NamingException(); + final String jndiName= "foobar"; + JndiTemplate jt = new JndiTemplate() { + public Object lookup(String name) throws NamingException { + assertTrue(jndiName.equals(name)); + throw nex; + } + }; + + LocalSlsbInvokerInterceptor si = new LocalSlsbInvokerInterceptor(); + si.setJndiName("foobar"); + // default resourceRef=false should cause this to fail, as java:/comp/env will not + // automatically be added + si.setJndiTemplate(jt); + try { + si.afterPropertiesSet(); + fail("Should have failed with naming exception"); + } + catch (NamingException ex) { + assertTrue(ex == nex); + } + } + + public void testInvokesMethodOnEjbInstance() throws Exception { + Object retVal = new Object(); + MockControl ejbControl = MockControl.createControl(LocalInterfaceWithBusinessMethods.class); + final LocalInterfaceWithBusinessMethods ejb = (LocalInterfaceWithBusinessMethods) ejbControl.getMock(); + ejb.targetMethod(); + ejbControl.setReturnValue(retVal, 1); + ejb.remove(); + ejbControl.setVoidCallable(1); + ejbControl.replay(); + + final String jndiName= "foobar"; + MockControl contextControl = contextControl(jndiName, ejb); + + LocalSlsbInvokerInterceptor si = configuredInterceptor(contextControl, jndiName); + + ProxyFactory pf = new ProxyFactory(new Class[] { BusinessMethods.class } ); + pf.addAdvice(si); + BusinessMethods target = (BusinessMethods) pf.getProxy(); + + assertTrue(target.targetMethod() == retVal); + + contextControl.verify(); + ejbControl.verify(); + } + + public void testInvokesMethodOnEjbInstanceWithSeparateBusinessMethods() throws Exception { + Object retVal = new Object(); + MockControl ejbControl = MockControl.createControl(LocalInterface.class); + final LocalInterface ejb = (LocalInterface) ejbControl.getMock(); + ejb.targetMethod(); + ejbControl.setReturnValue(retVal, 1); + ejb.remove(); + ejbControl.setVoidCallable(1); + ejbControl.replay(); + + final String jndiName= "foobar"; + MockControl contextControl = contextControl(jndiName, ejb); + + LocalSlsbInvokerInterceptor si = configuredInterceptor(contextControl, jndiName); + + ProxyFactory pf = new ProxyFactory(new Class[] { BusinessMethods.class } ); + pf.addAdvice(si); + BusinessMethods target = (BusinessMethods) pf.getProxy(); + + assertTrue(target.targetMethod() == retVal); + + contextControl.verify(); + ejbControl.verify(); + } + + private void testException(Exception expected) throws Exception { + MockControl ejbControl = MockControl.createControl(LocalInterfaceWithBusinessMethods.class); + final LocalInterfaceWithBusinessMethods ejb = (LocalInterfaceWithBusinessMethods) ejbControl.getMock(); + ejb.targetMethod(); + ejbControl.setThrowable(expected); + ejbControl.replay(); + + final String jndiName= "foobar"; + MockControl contextControl = contextControl(jndiName, ejb); + + LocalSlsbInvokerInterceptor si = configuredInterceptor(contextControl, jndiName); + + ProxyFactory pf = new ProxyFactory(new Class[] { LocalInterfaceWithBusinessMethods.class } ); + pf.addAdvice(si); + LocalInterfaceWithBusinessMethods target = (LocalInterfaceWithBusinessMethods) pf.getProxy(); + + try { + target.targetMethod(); + fail("Should have thrown exception"); + } + catch (Exception thrown) { + assertTrue(thrown == expected); + } + + contextControl.verify(); + ejbControl.verify(); + } + + public void testApplicationException() throws Exception { + testException(new ApplicationException()); + } + + protected MockControl contextControl(final String jndiName, final Object ejbInstance) + throws Exception { + + MockControl homeControl = MockControl.createControl(SlsbHome.class); + final SlsbHome mockHome = (SlsbHome) homeControl.getMock(); + mockHome.create(); + homeControl.setReturnValue(ejbInstance, 1); + homeControl.replay(); + + MockControl ctxControl = MockControl.createControl(Context.class); + final Context mockCtx = (Context) ctxControl.getMock(); + + mockCtx.lookup("java:comp/env/" + jndiName); + ctxControl.setReturnValue(mockHome); + mockCtx.close(); + ctxControl.setVoidCallable(); + ctxControl.replay(); + return ctxControl; + } + + protected LocalSlsbInvokerInterceptor configuredInterceptor(MockControl contextControl, final String jndiName) + throws Exception { + + final Context mockCtx = (Context) contextControl.getMock(); + LocalSlsbInvokerInterceptor si = new LocalSlsbInvokerInterceptor(); + si.setJndiTemplate(new JndiTemplate() { + protected Context createInitialContext() throws NamingException { + return mockCtx; + } + }); + si.setJndiName(jndiName); + si.setResourceRef(true); + si.afterPropertiesSet(); + + return si; + } + + + /** + * Needed so that we can mock the create() method. + */ + private interface SlsbHome extends EJBLocalHome { + + LocalInterface create() throws CreateException; + } + + + private interface BusinessMethods { + + Object targetMethod() throws ApplicationException; + } + + + private interface LocalInterface extends EJBLocalObject { + + Object targetMethod() throws ApplicationException; + } + + + private interface LocalInterfaceWithBusinessMethods extends LocalInterface, BusinessMethods { + } + + + private class ApplicationException extends Exception { + + public ApplicationException() { + super("appException"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ejb/access/LocalStatelessSessionProxyFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/ejb/access/LocalStatelessSessionProxyFactoryBeanTests.java new file mode 100644 index 00000000000..544d040aa9a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ejb/access/LocalStatelessSessionProxyFactoryBeanTests.java @@ -0,0 +1,210 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ejb.access; + +import java.lang.reflect.Proxy; + +import javax.ejb.CreateException; +import javax.ejb.EJBLocalHome; +import javax.ejb.EJBLocalObject; +import javax.naming.NamingException; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jndi.JndiTemplate; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @since 21.05.2003 + */ +public class LocalStatelessSessionProxyFactoryBeanTests extends TestCase { + + public void testInvokesMethod() throws Exception { + final int value = 11; + final String jndiName = "foo"; + + MockControl ec = MockControl.createControl(MyEjb.class); + MyEjb myEjb = (MyEjb) ec.getMock(); + myEjb.getValue(); + ec.setReturnValue(value, 1); + myEjb.remove(); + ec.setVoidCallable(1); + ec.replay(); + + MockControl mc = MockControl.createControl(MyHome.class); + final MyHome home = (MyHome) mc.getMock(); + home.create(); + mc.setReturnValue(myEjb, 1); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + public Object lookup(String name) throws NamingException { + // parameterize + assertTrue(name.equals("java:comp/env/" + jndiName)); + return home; + } + }; + + LocalStatelessSessionProxyFactoryBean fb = new LocalStatelessSessionProxyFactoryBean(); + fb.setJndiName(jndiName); + fb.setResourceRef(true); + fb.setBusinessInterface(MyBusinessMethods.class); + fb.setJndiTemplate(jt); + + // Need lifecycle methods + fb.afterPropertiesSet(); + + MyBusinessMethods mbm = (MyBusinessMethods) fb.getObject(); + assertTrue(Proxy.isProxyClass(mbm.getClass())); + assertTrue(mbm.getValue() == value); + mc.verify(); + ec.verify(); + } + + public void testInvokesMethodOnEjb3StyleBean() throws Exception { + final int value = 11; + final String jndiName = "foo"; + + MockControl ec = MockControl.createControl(MyEjb.class); + final MyEjb myEjb = (MyEjb) ec.getMock(); + myEjb.getValue(); + ec.setReturnValue(value, 1); + ec.replay(); + + JndiTemplate jt = new JndiTemplate() { + public Object lookup(String name) throws NamingException { + // parameterize + assertTrue(name.equals("java:comp/env/" + jndiName)); + return myEjb; + } + }; + + LocalStatelessSessionProxyFactoryBean fb = new LocalStatelessSessionProxyFactoryBean(); + fb.setJndiName(jndiName); + fb.setResourceRef(true); + fb.setBusinessInterface(MyBusinessMethods.class); + fb.setJndiTemplate(jt); + + // Need lifecycle methods + fb.afterPropertiesSet(); + + MyBusinessMethods mbm = (MyBusinessMethods) fb.getObject(); + assertTrue(Proxy.isProxyClass(mbm.getClass())); + assertTrue(mbm.getValue() == value); + ec.verify(); + } + + public void testCreateException() throws Exception { + final String jndiName = "foo"; + + final CreateException cex = new CreateException(); + MockControl mc = MockControl.createControl(MyHome.class); + final MyHome home = (MyHome) mc.getMock(); + home.create(); + mc.setThrowable(cex); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + public Object lookup(String name) throws NamingException { + // parameterize + assertTrue(name.equals(jndiName)); + return home; + } + }; + + LocalStatelessSessionProxyFactoryBean fb = new LocalStatelessSessionProxyFactoryBean(); + fb.setJndiName(jndiName); + fb.setResourceRef(false); // no java:comp/env prefix + fb.setBusinessInterface(MyBusinessMethods.class); + assertEquals(fb.getBusinessInterface(), MyBusinessMethods.class); + fb.setJndiTemplate(jt); + + // Need lifecycle methods + fb.afterPropertiesSet(); + + MyBusinessMethods mbm = (MyBusinessMethods) fb.getObject(); + assertTrue(Proxy.isProxyClass(mbm.getClass())); + + try { + mbm.getValue(); + fail("Should have failed to create EJB"); + } + catch (EjbAccessException ex) { + assertSame(cex, ex.getCause()); + } + + mc.verify(); + } + + public void testNoBusinessInterfaceSpecified() throws Exception { + // Will do JNDI lookup to get home but won't call create + // Could actually try to figure out interface from create? + final String jndiName = "foo"; + + MockControl mc = MockControl.createControl(MyHome.class); + final MyHome home = (MyHome) mc.getMock(); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + public Object lookup(String name) throws NamingException { + // parameterize + assertTrue(name.equals("java:comp/env/" + jndiName)); + return home; + } + }; + + LocalStatelessSessionProxyFactoryBean fb = new LocalStatelessSessionProxyFactoryBean(); + fb.setJndiName(jndiName); + fb.setResourceRef(true); + // Don't set business interface + fb.setJndiTemplate(jt); + + // Check it's a singleton + assertTrue(fb.isSingleton()); + + try { + fb.afterPropertiesSet(); + fail("Should have failed to create EJB"); + } + catch (IllegalArgumentException ex) { + // TODO more appropriate exception? + assertTrue(ex.getMessage().indexOf("businessInterface") != 1); + } + + // Expect no methods on home + mc.verify(); + } + + + public static interface MyHome extends EJBLocalHome { + + MyBusinessMethods create() throws CreateException; + } + + + public static interface MyBusinessMethods { + + int getValue(); + } + + + public static interface MyEjb extends EJBLocalObject, MyBusinessMethods { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ejb/access/SimpleRemoteSlsbInvokerInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/ejb/access/SimpleRemoteSlsbInvokerInterceptorTests.java new file mode 100644 index 00000000000..eb712909a9b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ejb/access/SimpleRemoteSlsbInvokerInterceptorTests.java @@ -0,0 +1,416 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ejb.access; + +import java.rmi.ConnectException; +import java.rmi.RemoteException; + +import javax.ejb.CreateException; +import javax.ejb.EJBHome; +import javax.ejb.EJBObject; +import javax.naming.Context; +import javax.naming.NamingException; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.jndi.JndiTemplate; +import org.springframework.remoting.RemoteAccessException; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class SimpleRemoteSlsbInvokerInterceptorTests extends TestCase { + + private MockControl contextControl( + String jndiName, RemoteInterface ejbInstance, int createCount, int lookupCount, int closeCount) + throws Exception { + + MockControl homeControl = MockControl.createControl(SlsbHome.class); + final SlsbHome mockHome = (SlsbHome) homeControl.getMock(); + mockHome.create(); + homeControl.setReturnValue(ejbInstance, createCount); + homeControl.replay(); + + MockControl ctxControl = MockControl.createControl(Context.class); + final Context mockCtx = (Context) ctxControl.getMock(); + + mockCtx.lookup("java:comp/env/" + jndiName); + ctxControl.setReturnValue(mockHome, lookupCount); + mockCtx.close(); + ctxControl.setVoidCallable(closeCount); + ctxControl.replay(); + + return ctxControl; + } + + private SimpleRemoteSlsbInvokerInterceptor configuredInterceptor( + MockControl ctxControl, String jndiName) throws Exception { + + final Context mockCtx = (Context) ctxControl.getMock(); + SimpleRemoteSlsbInvokerInterceptor si = createInterceptor(); + si.setJndiTemplate(new JndiTemplate() { + protected Context createInitialContext() { + return mockCtx; + } + }); + si.setResourceRef(true); + si.setJndiName(jndiName); + + return si; + } + + protected SimpleRemoteSlsbInvokerInterceptor createInterceptor() { + return new SimpleRemoteSlsbInvokerInterceptor(); + } + + protected Object configuredProxy(SimpleRemoteSlsbInvokerInterceptor si, Class ifc) throws NamingException { + si.afterPropertiesSet(); + ProxyFactory pf = new ProxyFactory(new Class[] {ifc}); + pf.addAdvice(si); + return pf.getProxy(); + } + + + public void testPerformsLookup() throws Exception { + MockControl ejbControl = MockControl.createControl(RemoteInterface.class); + RemoteInterface ejb = (RemoteInterface) ejbControl.getMock(); + ejbControl.replay(); + + String jndiName= "foobar"; + MockControl contextControl = contextControl(jndiName, ejb, 1, 1, 1); + + SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(contextControl, jndiName); + RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class); + + contextControl.verify(); + } + + public void testPerformsLookupWithAccessContext() throws Exception { + MockControl ejbControl = MockControl.createControl(RemoteInterface.class); + RemoteInterface ejb = (RemoteInterface) ejbControl.getMock(); + ejb.targetMethod(); + ejbControl.setReturnValue(null); + ejbControl.replay(); + + String jndiName= "foobar"; + MockControl contextControl = contextControl(jndiName, ejb, 1, 1, 2); + + SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(contextControl, jndiName); + si.setExposeAccessContext(true); + RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class); + assertNull(target.targetMethod()); + + contextControl.verify(); + } + + public void testLookupFailure() throws Exception { + final NamingException nex = new NamingException(); + final String jndiName = "foobar"; + JndiTemplate jt = new JndiTemplate() { + public Object lookup(String name) throws NamingException { + assertTrue(jndiName.equals(name)); + throw nex; + } + }; + + SimpleRemoteSlsbInvokerInterceptor si = new SimpleRemoteSlsbInvokerInterceptor(); + si.setJndiName("foobar"); + // default resourceRef=false should cause this to fail, as java:/comp/env will not + // automatically be added + si.setJndiTemplate(jt); + try { + si.afterPropertiesSet(); + fail("Should have failed with naming exception"); + } + catch (NamingException ex) { + assertTrue(ex == nex); + } + } + + public void testInvokesMethodOnEjbInstance() throws Exception { + doTestInvokesMethodOnEjbInstance(true, true); + } + + public void testInvokesMethodOnEjbInstanceWithLazyLookup() throws Exception { + doTestInvokesMethodOnEjbInstance(false, true); + } + + public void testInvokesMethodOnEjbInstanceWithLazyLookupAndNoCache() throws Exception { + doTestInvokesMethodOnEjbInstance(false, false); + } + + public void testInvokesMethodOnEjbInstanceWithNoCache() throws Exception { + doTestInvokesMethodOnEjbInstance(true, false); + } + + private void doTestInvokesMethodOnEjbInstance(boolean lookupHomeOnStartup, boolean cacheHome) throws Exception { + Object retVal = new Object(); + MockControl ejbControl = MockControl.createControl(RemoteInterface.class); + final RemoteInterface ejb = (RemoteInterface) ejbControl.getMock(); + ejb.targetMethod(); + ejbControl.setReturnValue(retVal, 2); + ejb.remove(); + ejbControl.setVoidCallable(2); + ejbControl.replay(); + + int lookupCount = 1; + if (!cacheHome) { + lookupCount++; + if (lookupHomeOnStartup) { + lookupCount++; + } + } + + final String jndiName= "foobar"; + MockControl contextControl = contextControl(jndiName, ejb, 2, lookupCount, lookupCount); + + SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(contextControl, jndiName); + si.setLookupHomeOnStartup(lookupHomeOnStartup); + si.setCacheHome(cacheHome); + + RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class); + assertTrue(target.targetMethod() == retVal); + assertTrue(target.targetMethod() == retVal); + + contextControl.verify(); + ejbControl.verify(); + } + + public void testInvokesMethodOnEjbInstanceWithHomeInterface() throws Exception { + Object retVal = new Object(); + MockControl ejbControl = MockControl.createControl(RemoteInterface.class); + final RemoteInterface ejb = (RemoteInterface) ejbControl.getMock(); + ejb.targetMethod(); + ejbControl.setReturnValue(retVal, 1); + ejb.remove(); + ejbControl.setVoidCallable(1); + ejbControl.replay(); + + final String jndiName= "foobar"; + MockControl contextControl = contextControl(jndiName, ejb, 1, 1, 1); + + SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(contextControl, jndiName); + si.setHomeInterface(SlsbHome.class); + + RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class); + assertTrue(target.targetMethod() == retVal); + + contextControl.verify(); + ejbControl.verify(); + } + + public void testInvokesMethodOnEjbInstanceWithRemoteException() throws Exception { + MockControl ejbControl = MockControl.createControl(RemoteInterface.class); + final RemoteInterface ejb = (RemoteInterface) ejbControl.getMock(); + ejb.targetMethod(); + ejbControl.setThrowable(new RemoteException(), 1); + ejb.remove(); + ejbControl.setVoidCallable(1); + ejbControl.replay(); + + final String jndiName= "foobar"; + MockControl contextControl = contextControl(jndiName, ejb, 1, 1, 1); + + SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(contextControl, jndiName); + + RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class); + try { + target.targetMethod(); + fail("Should have thrown RemoteException"); + } + catch (RemoteException ex) { + // expected + } + + contextControl.verify(); + ejbControl.verify(); + } + + public void testInvokesMethodOnEjbInstanceWithConnectExceptionWithRefresh() throws Exception { + doTestInvokesMethodOnEjbInstanceWithConnectExceptionWithRefresh(true, true); + } + + public void testInvokesMethodOnEjbInstanceWithConnectExceptionWithRefreshAndLazyLookup() throws Exception { + doTestInvokesMethodOnEjbInstanceWithConnectExceptionWithRefresh(false, true); + } + + public void testInvokesMethodOnEjbInstanceWithConnectExceptionWithRefreshAndLazyLookupAndNoCache() throws Exception { + doTestInvokesMethodOnEjbInstanceWithConnectExceptionWithRefresh(false, false); + } + + public void testInvokesMethodOnEjbInstanceWithConnectExceptionWithRefreshAndNoCache() throws Exception { + doTestInvokesMethodOnEjbInstanceWithConnectExceptionWithRefresh(true, false); + } + + private void doTestInvokesMethodOnEjbInstanceWithConnectExceptionWithRefresh( + boolean lookupHomeOnStartup, boolean cacheHome) throws Exception { + + MockControl ejbControl = MockControl.createControl(RemoteInterface.class); + final RemoteInterface ejb = (RemoteInterface) ejbControl.getMock(); + ejb.targetMethod(); + ejbControl.setThrowable(new ConnectException(""), 2); + ejb.remove(); + ejbControl.setVoidCallable(2); + ejbControl.replay(); + + int lookupCount = 2; + if (!cacheHome) { + lookupCount++; + if (lookupHomeOnStartup) { + lookupCount++; + } + } + + final String jndiName= "foobar"; + MockControl contextControl = contextControl(jndiName, ejb, 2, lookupCount, lookupCount); + + SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(contextControl, jndiName); + si.setRefreshHomeOnConnectFailure(true); + si.setLookupHomeOnStartup(lookupHomeOnStartup); + si.setCacheHome(cacheHome); + + RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class); + try { + target.targetMethod(); + fail("Should have thrown RemoteException"); + } + catch (ConnectException ex) { + // expected + } + + contextControl.verify(); + ejbControl.verify(); + } + + public void testInvokesMethodOnEjbInstanceWithBusinessInterface() throws Exception { + Object retVal = new Object(); + MockControl ejbControl = MockControl.createControl(RemoteInterface.class); + final RemoteInterface ejb = (RemoteInterface) ejbControl.getMock(); + ejb.targetMethod(); + ejbControl.setReturnValue(retVal, 1); + ejb.remove(); + ejbControl.setVoidCallable(1); + ejbControl.replay(); + + final String jndiName= "foobar"; + MockControl contextControl = contextControl(jndiName, ejb, 1, 1, 1); + + SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(contextControl, jndiName); + + BusinessInterface target = (BusinessInterface) configuredProxy(si, BusinessInterface.class); + assertTrue(target.targetMethod() == retVal); + + contextControl.verify(); + ejbControl.verify(); + } + + public void testInvokesMethodOnEjbInstanceWithBusinessInterfaceWithRemoteException() throws Exception { + MockControl ejbControl = MockControl.createControl(RemoteInterface.class); + final RemoteInterface ejb = (RemoteInterface) ejbControl.getMock(); + ejb.targetMethod(); + ejbControl.setThrowable(new RemoteException(), 1); + ejb.remove(); + ejbControl.setVoidCallable(1); + ejbControl.replay(); + + final String jndiName= "foobar"; + MockControl contextControl = contextControl(jndiName, ejb, 1, 1, 1); + + SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(contextControl, jndiName); + + BusinessInterface target = (BusinessInterface) configuredProxy(si, BusinessInterface.class); + try { + target.targetMethod(); + fail("Should have thrown RemoteAccessException"); + } + catch (RemoteAccessException ex) { + // expected + } + + contextControl.verify(); + ejbControl.verify(); + } + + public void testApplicationException() throws Exception { + doTestException(new ApplicationException()); + } + + public void testRemoteException() throws Exception { + doTestException(new RemoteException()); + } + + private void doTestException(Exception expected) throws Exception { + MockControl ejbControl = MockControl.createControl(RemoteInterface.class); + final RemoteInterface ejb = (RemoteInterface) ejbControl.getMock(); + ejb.targetMethod(); + ejbControl.setThrowable(expected); + ejb.remove(); + ejbControl.setVoidCallable(1); + ejbControl.replay(); + + final String jndiName= "foobar"; + MockControl contextControl = contextControl(jndiName, ejb, 1, 1, 1); + + SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(contextControl, jndiName); + + RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class); + try { + target.targetMethod(); + fail("Should have thrown remote exception"); + } + catch (Exception thrown) { + assertTrue(thrown == expected); + } + + contextControl.verify(); + ejbControl.verify(); + } + + + /** + * Needed so that we can mock create() method. + */ + protected interface SlsbHome extends EJBHome { + + EJBObject create() throws RemoteException, CreateException; + } + + + protected interface RemoteInterface extends EJBObject { + + // Also business exception!? + Object targetMethod() throws RemoteException, ApplicationException; + } + + + protected interface BusinessInterface { + + Object targetMethod() throws ApplicationException; + } + + + protected class ApplicationException extends Exception { + + public ApplicationException() { + super("appException"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ejb/access/SimpleRemoteStatelessSessionProxyFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/ejb/access/SimpleRemoteStatelessSessionProxyFactoryBeanTests.java new file mode 100644 index 00000000000..c8717d11e84 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ejb/access/SimpleRemoteStatelessSessionProxyFactoryBeanTests.java @@ -0,0 +1,321 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ejb.access; + +import java.lang.reflect.Proxy; +import java.rmi.RemoteException; + +import javax.ejb.CreateException; +import javax.ejb.EJBHome; +import javax.ejb.EJBObject; +import javax.naming.NamingException; + +import org.easymock.MockControl; + +import org.springframework.jndi.JndiTemplate; +import org.springframework.remoting.RemoteAccessException; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @since 21.05.2003 + */ +public class SimpleRemoteStatelessSessionProxyFactoryBeanTests extends SimpleRemoteSlsbInvokerInterceptorTests { + + protected SimpleRemoteSlsbInvokerInterceptor createInterceptor() { + return new SimpleRemoteStatelessSessionProxyFactoryBean(); + } + + protected Object configuredProxy(SimpleRemoteSlsbInvokerInterceptor si, Class ifc) throws NamingException { + SimpleRemoteStatelessSessionProxyFactoryBean fb = (SimpleRemoteStatelessSessionProxyFactoryBean) si; + fb.setBusinessInterface(ifc); + fb.afterPropertiesSet(); + return fb.getObject(); + } + + public void testInvokesMethod() throws Exception { + final int value = 11; + final String jndiName = "foo"; + + MockControl ec = MockControl.createControl(MyEjb.class); + MyEjb myEjb = (MyEjb) ec.getMock(); + myEjb.getValue(); + ec.setReturnValue(value, 1); + myEjb.remove(); + ec.setVoidCallable(1); + ec.replay(); + + MockControl mc = MockControl.createControl(MyHome.class); + final MyHome home = (MyHome) mc.getMock(); + home.create(); + mc.setReturnValue(myEjb, 1); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + public Object lookup(String name) { + // parameterize + assertTrue(name.equals("java:comp/env/" + jndiName)); + return home; + } + }; + + SimpleRemoteStatelessSessionProxyFactoryBean fb = new SimpleRemoteStatelessSessionProxyFactoryBean(); + fb.setJndiName(jndiName); + fb.setResourceRef(true); + fb.setBusinessInterface(MyBusinessMethods.class); + fb.setJndiTemplate(jt); + + // Need lifecycle methods + fb.afterPropertiesSet(); + + MyBusinessMethods mbm = (MyBusinessMethods) fb.getObject(); + assertTrue(Proxy.isProxyClass(mbm.getClass())); + assertEquals("Returns expected value", value, mbm.getValue()); + mc.verify(); + ec.verify(); + } + + public void testInvokesMethodOnEjb3StyleBean() throws Exception { + final int value = 11; + final String jndiName = "foo"; + + MockControl ec = MockControl.createControl(MyEjb.class); + final MyEjb myEjb = (MyEjb) ec.getMock(); + myEjb.getValue(); + ec.setReturnValue(value, 1); + ec.replay(); + + JndiTemplate jt = new JndiTemplate() { + public Object lookup(String name) { + // parameterize + assertTrue(name.equals("java:comp/env/" + jndiName)); + return myEjb; + } + }; + + SimpleRemoteStatelessSessionProxyFactoryBean fb = new SimpleRemoteStatelessSessionProxyFactoryBean(); + fb.setJndiName(jndiName); + fb.setResourceRef(true); + fb.setBusinessInterface(MyBusinessMethods.class); + fb.setJndiTemplate(jt); + + // Need lifecycle methods + fb.afterPropertiesSet(); + + MyBusinessMethods mbm = (MyBusinessMethods) fb.getObject(); + assertTrue(Proxy.isProxyClass(mbm.getClass())); + assertEquals("Returns expected value", value, mbm.getValue()); + ec.verify(); + } + + public void testRemoteException() throws Exception { + final RemoteException rex = new RemoteException(); + final String jndiName = "foo"; + + MockControl ec = MockControl.createControl(MyEjb.class); + MyEjb myEjb = (MyEjb) ec.getMock(); + myEjb.getValue(); + ec.setThrowable(rex); + // TODO might want to control this behaviour... + // Do we really want to call remove after a remote exception? + myEjb.remove(); + ec.setVoidCallable(1); + ec.replay(); + + MockControl mc = MockControl.createControl(MyHome.class); + final MyHome home = (MyHome) mc.getMock(); + home.create(); + mc.setReturnValue(myEjb, 1); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + public Object lookup(String name) { + // parameterize + assertTrue(name.equals("java:comp/env/" + jndiName)); + return home; + } + }; + + SimpleRemoteStatelessSessionProxyFactoryBean fb = new SimpleRemoteStatelessSessionProxyFactoryBean(); + fb.setJndiName(jndiName); + fb.setResourceRef(true); + fb.setBusinessInterface(MyBusinessMethods.class); + fb.setJndiTemplate(jt); + + // Need lifecycle methods + fb.afterPropertiesSet(); + + MyBusinessMethods mbm = (MyBusinessMethods) fb.getObject(); + assertTrue(Proxy.isProxyClass(mbm.getClass())); + try { + mbm.getValue(); + fail("Should've thrown remote exception"); + } + catch (RemoteException ex) { + assertSame("Threw expected RemoteException", rex, ex); + } + mc.verify(); + ec.verify(); + } + + public void testCreateException() throws Exception { + final String jndiName = "foo"; + + final CreateException cex = new CreateException(); + MockControl mc = MockControl.createControl(MyHome.class); + final MyHome home = (MyHome) mc.getMock(); + home.create(); + mc.setThrowable(cex); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + public Object lookup(String name) { + // parameterize + assertTrue(name.equals(jndiName)); + return home; + } + }; + + SimpleRemoteStatelessSessionProxyFactoryBean fb = new SimpleRemoteStatelessSessionProxyFactoryBean(); + fb.setJndiName(jndiName); + // rely on default setting of resourceRef=false, no auto addition of java:/comp/env prefix + fb.setBusinessInterface(MyBusinessMethods.class); + assertEquals(fb.getBusinessInterface(), MyBusinessMethods.class); + fb.setJndiTemplate(jt); + + // Need lifecycle methods + fb.afterPropertiesSet(); + + MyBusinessMethods mbm = (MyBusinessMethods) fb.getObject(); + assertTrue(Proxy.isProxyClass(mbm.getClass())); + + try { + mbm.getValue(); + fail("Should have failed to create EJB"); + } + catch (RemoteException ex) { + // expected + } + + mc.verify(); + } + + public void testCreateExceptionWithLocalBusinessInterface() throws Exception { + final String jndiName = "foo"; + + final CreateException cex = new CreateException(); + MockControl mc = MockControl.createControl(MyHome.class); + final MyHome home = (MyHome) mc.getMock(); + home.create(); + mc.setThrowable(cex); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + public Object lookup(String name) { + // parameterize + assertTrue(name.equals(jndiName)); + return home; + } + }; + + SimpleRemoteStatelessSessionProxyFactoryBean fb = new SimpleRemoteStatelessSessionProxyFactoryBean(); + fb.setJndiName(jndiName); + // rely on default setting of resourceRef=false, no auto addition of java:/comp/env prefix + fb.setBusinessInterface(MyLocalBusinessMethods.class); + assertEquals(fb.getBusinessInterface(), MyLocalBusinessMethods.class); + fb.setJndiTemplate(jt); + + // Need lifecycle methods + fb.afterPropertiesSet(); + + MyLocalBusinessMethods mbm = (MyLocalBusinessMethods) fb.getObject(); + assertTrue(Proxy.isProxyClass(mbm.getClass())); + + try { + mbm.getValue(); + fail("Should have failed to create EJB"); + } + catch (RemoteAccessException ex) { + assertTrue(ex.getCause() == cex); + } + + mc.verify(); + } + + public void testNoBusinessInterfaceSpecified() throws Exception { + // Will do JNDI lookup to get home but won't call create + // Could actually try to figure out interface from create? + final String jndiName = "foo"; + + MockControl mc = MockControl.createControl(MyHome.class); + final MyHome home = (MyHome) mc.getMock(); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + public Object lookup(String name) throws NamingException { + // parameterize + assertTrue(name.equals(jndiName)); + return home; + } + }; + + SimpleRemoteStatelessSessionProxyFactoryBean fb = new SimpleRemoteStatelessSessionProxyFactoryBean(); + fb.setJndiName(jndiName); + // rely on default setting of resourceRef=false, no auto addition of java:/comp/env prefix + // Don't set business interface + fb.setJndiTemplate(jt); + + // Check it's a singleton + assertTrue(fb.isSingleton()); + + try { + fb.afterPropertiesSet(); + fail("Should have failed to create EJB"); + } + catch (IllegalArgumentException ex) { + // TODO more appropriate exception? + assertTrue(ex.getMessage().indexOf("businessInterface") != 1); + } + + // Expect no methods on home + mc.verify(); + } + + + protected static interface MyHome extends EJBHome { + + MyBusinessMethods create() throws CreateException, RemoteException; + } + + + protected static interface MyBusinessMethods { + + int getValue() throws RemoteException; + } + + + protected static interface MyLocalBusinessMethods { + + int getValue(); + } + + + protected static interface MyEjb extends EJBObject, MyBusinessMethods { + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ejb/config/JeeNamespaceHandlerEventTests.java b/org.springframework.testsuite/src/test/java/org/springframework/ejb/config/JeeNamespaceHandlerEventTests.java new file mode 100644 index 00000000000..406198b3848 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ejb/config/JeeNamespaceHandlerEventTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2002-2006 the original author 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.ejb.config; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.parsing.CollectingReaderEventListener; +import org.springframework.beans.factory.parsing.ComponentDefinition; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Torsten Juergeleit + * @author Juergen Hoeller + */ +public class JeeNamespaceHandlerEventTests extends TestCase { + + private CollectingReaderEventListener eventListener = new CollectingReaderEventListener(); + + private XmlBeanDefinitionReader reader; + + private DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + + + public void setUp() throws Exception { + this.reader = new XmlBeanDefinitionReader(this.beanFactory); + this.reader.setEventListener(this.eventListener); + this.reader.loadBeanDefinitions(new ClassPathResource("jeeNamespaceHandlerTests.xml", getClass())); + } + + public void testJndiLookupComponentEventReceived() { + ComponentDefinition component = this.eventListener.getComponentDefinition("simple"); + assertTrue(component instanceof BeanComponentDefinition); + } + + public void testLocalSlsbComponentEventReceived() { + ComponentDefinition component = this.eventListener.getComponentDefinition("simpleLocalEjb"); + assertTrue(component instanceof BeanComponentDefinition); + } + + public void testRemoteSlsbComponentEventReceived() { + ComponentDefinition component = this.eventListener.getComponentDefinition("simpleRemoteEjb"); + assertTrue(component instanceof BeanComponentDefinition); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ejb/config/JeeNamespaceHandlerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/ejb/config/JeeNamespaceHandlerTests.java new file mode 100644 index 00000000000..a5681fa7737 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ejb/config/JeeNamespaceHandlerTests.java @@ -0,0 +1,125 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ejb.config; + +import junit.framework.TestCase; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.io.ClassPathResource; +import org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean; +import org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean; +import org.springframework.jndi.JndiObjectFactoryBean; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class JeeNamespaceHandlerTests extends TestCase { + + private ConfigurableListableBeanFactory beanFactory; + + protected void setUp() throws Exception { + GenericApplicationContext ctx = new GenericApplicationContext(); + new XmlBeanDefinitionReader(ctx).loadBeanDefinitions( + new ClassPathResource("jeeNamespaceHandlerTests.xml", getClass())); + ctx.refresh(); + this.beanFactory = ctx.getBeanFactory(); + this.beanFactory.getBeanNamesForType(ITestBean.class); + } + + public void testSimpleDefinition() throws Exception { + BeanDefinition beanDefinition = this.beanFactory.getMergedBeanDefinition("simple"); + assertEquals(JndiObjectFactoryBean.class.getName(), beanDefinition.getBeanClassName()); + assertPropertyValue(beanDefinition, "jndiName", "jdbc/MyDataSource"); + assertPropertyValue(beanDefinition, "resourceRef", "true"); + } + + public void testComplexDefinition() throws Exception { + BeanDefinition beanDefinition = this.beanFactory.getMergedBeanDefinition("complex"); + assertEquals(JndiObjectFactoryBean.class.getName(), beanDefinition.getBeanClassName()); + assertPropertyValue(beanDefinition, "jndiName", "jdbc/MyDataSource"); + assertPropertyValue(beanDefinition, "resourceRef", "true"); + assertPropertyValue(beanDefinition, "cache", "true"); + assertPropertyValue(beanDefinition, "lookupOnStartup", "true"); + assertPropertyValue(beanDefinition, "exposeAccessContext", "true"); + assertPropertyValue(beanDefinition, "expectedType", "com.myapp.DefaultFoo"); + assertPropertyValue(beanDefinition, "proxyInterface", "com.myapp.Foo"); + assertPropertyValue(beanDefinition, "defaultObject", "myValue"); + } + + public void testWithEnvironment() throws Exception { + BeanDefinition beanDefinition = this.beanFactory.getMergedBeanDefinition("withEnvironment"); + assertPropertyValue(beanDefinition, "jndiEnvironment", "foo=bar"); + assertPropertyValue(beanDefinition, "defaultObject", new RuntimeBeanReference("myBean")); + } + + public void testWithReferencedEnvironment() throws Exception { + BeanDefinition beanDefinition = this.beanFactory.getMergedBeanDefinition("withReferencedEnvironment"); + assertPropertyValue(beanDefinition, "jndiEnvironment", new RuntimeBeanReference("myEnvironment")); + assertFalse(beanDefinition.getPropertyValues().contains("environmentRef")); + } + + public void testSimpleLocalSlsb() throws Exception { + BeanDefinition beanDefinition = this.beanFactory.getMergedBeanDefinition("simpleLocalEjb"); + assertEquals(LocalStatelessSessionProxyFactoryBean.class.getName(), beanDefinition.getBeanClassName()); + assertPropertyValue(beanDefinition, "businessInterface", ITestBean.class.getName()); + assertPropertyValue(beanDefinition, "jndiName", "ejb/MyLocalBean"); + } + + public void testSimpleRemoteSlsb() throws Exception { + BeanDefinition beanDefinition = this.beanFactory.getMergedBeanDefinition("simpleRemoteEjb"); + assertEquals(SimpleRemoteStatelessSessionProxyFactoryBean.class.getName(), beanDefinition.getBeanClassName()); + assertPropertyValue(beanDefinition, "businessInterface", ITestBean.class.getName()); + assertPropertyValue(beanDefinition, "jndiName", "ejb/MyRemoteBean"); + } + + public void testComplexLocalSlsb() throws Exception { + BeanDefinition beanDefinition = this.beanFactory.getMergedBeanDefinition("complexLocalEjb"); + assertEquals(LocalStatelessSessionProxyFactoryBean.class.getName(), beanDefinition.getBeanClassName()); + assertPropertyValue(beanDefinition, "businessInterface", ITestBean.class.getName()); + assertPropertyValue(beanDefinition, "jndiName", "ejb/MyLocalBean"); + assertPropertyValue(beanDefinition, "cacheHome", "true"); + assertPropertyValue(beanDefinition, "lookupHomeOnStartup", "true"); + assertPropertyValue(beanDefinition, "resourceRef", "true"); + assertPropertyValue(beanDefinition, "jndiEnvironment", "foo=bar"); + } + + public void testComplexRemoteSlsb() throws Exception { + BeanDefinition beanDefinition = this.beanFactory.getMergedBeanDefinition("complexRemoteEjb"); + assertEquals(SimpleRemoteStatelessSessionProxyFactoryBean.class.getName(), beanDefinition.getBeanClassName()); + assertPropertyValue(beanDefinition, "businessInterface", ITestBean.class.getName()); + assertPropertyValue(beanDefinition, "jndiName", "ejb/MyRemoteBean"); + assertPropertyValue(beanDefinition, "cacheHome", "true"); + assertPropertyValue(beanDefinition, "lookupHomeOnStartup", "true"); + assertPropertyValue(beanDefinition, "resourceRef", "true"); + assertPropertyValue(beanDefinition, "jndiEnvironment", "foo=bar"); + assertPropertyValue(beanDefinition, "homeInterface", "org.springframework.beans.ITestBean"); + assertPropertyValue(beanDefinition, "refreshHomeOnConnectFailure", "true"); + assertPropertyValue(beanDefinition, "cacheSessionBean", "true"); + } + + private void assertPropertyValue(BeanDefinition beanDefinition, String propertyName, Object expectedValue) { + assertEquals("Property '" + propertyName + "' incorrect", + expectedValue, beanDefinition.getPropertyValues().getPropertyValue(propertyName).getValue()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ejb/config/jeeNamespaceHandlerTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/ejb/config/jeeNamespaceHandlerTests.xml new file mode 100644 index 00000000000..acd3a192ef5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ejb/config/jeeNamespaceHandlerTests.xml @@ -0,0 +1,71 @@ + + + + + + + jdbc/MyDataSource + + + + + + + + + + + foo=bar + + + + + + bar + + + + + + + foo=bar + + + + + + + foo=bar + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ejb/support/EjbSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/ejb/support/EjbSupportTests.java new file mode 100644 index 00000000000..426fdfb45b2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ejb/support/EjbSupportTests.java @@ -0,0 +1,224 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ejb.support; + +import java.rmi.RemoteException; + +import javax.ejb.CreateException; +import javax.ejb.EJBException; +import javax.ejb.MessageDrivenContext; +import javax.ejb.SessionContext; +import javax.jms.Message; +import javax.naming.NamingException; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.BeansException; +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.access.BeanFactoryLocator; +import org.springframework.beans.factory.access.BeanFactoryReference; +import org.springframework.beans.factory.access.BootstrapException; +import org.springframework.beans.factory.support.StaticListableBeanFactory; +import org.springframework.mock.jndi.SimpleNamingContextBuilder; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @since 21.05.2003 + */ +public class EjbSupportTests extends TestCase { + + public void testSfsb() throws CreateException { + MockControl mc = MockControl.createControl(SessionContext.class); + SessionContext sc = (SessionContext) mc.getMock(); + mc.replay(); + + final BeanFactory bf = new StaticListableBeanFactory(); + BeanFactoryLocator bfl = new BeanFactoryLocator() { + public BeanFactoryReference useBeanFactory(String factoryKey) + throws FatalBeanException { + return new BeanFactoryReference() { + public BeanFactory getFactory() { + return bf; + } + public void release() throws FatalBeanException { + // nothing to do in default implementation + } + }; + } + }; + + // Basically the test is what needed to be implemented here! + class MySfsb extends AbstractStatefulSessionBean { + public void ejbCreate() throws CreateException { + loadBeanFactory(); + assertTrue(getBeanFactory() == bf); + } + public void ejbActivate() throws EJBException, RemoteException { + throw new UnsupportedOperationException("ejbActivate"); + } + public void ejbPassivate() throws EJBException, RemoteException { + throw new UnsupportedOperationException("ejbPassivate"); + } + + } + + MySfsb sfsb = new MySfsb(); + sfsb.setBeanFactoryLocator(bfl); + sfsb.setSessionContext(sc); + sfsb.ejbCreate(); + assertTrue(sc == sfsb.getSessionContext()); + } + + /** + * Check there's a helpful message if no JNDI key is present. + */ + public void testHelpfulNamingLookupMessage() throws NamingException, CreateException { + SimpleNamingContextBuilder.emptyActivatedContextBuilder(); + + MockControl mc = MockControl.createControl(SessionContext.class); + SessionContext sc = (SessionContext) mc.getMock(); + mc.replay(); + + // Leave with default XmlBeanFactoryLoader + + // Basically the test is what needed to be implemented here! + AbstractStatelessSessionBean slsb = new AbstractStatelessSessionBean() { + public void onEjbCreate() { + } + }; + + slsb.setSessionContext(sc); + try { + slsb.ejbCreate(); + fail(); + } + catch (BeansException ex) { + assertTrue(ex.getMessage().indexOf("environment") != -1); + assertTrue(ex.getMessage().indexOf("ejb/BeanFactoryPath") != -1); + } + } + + public void testSlsb() throws Exception { + MockControl mc = MockControl.createControl(SessionContext.class); + SessionContext sc = (SessionContext) mc.getMock(); + mc.replay(); + + final BeanFactory bf = new StaticListableBeanFactory(); + BeanFactoryLocator bfl = new BeanFactoryLocator() { + public BeanFactoryReference useBeanFactory(String factoryKey) throws FatalBeanException { + return new BeanFactoryReference() { + public BeanFactory getFactory() { + return bf; + } + public void release() throws FatalBeanException { + // nothing to do in default implementation + } + }; + } + }; + + AbstractStatelessSessionBean slsb = new AbstractStatelessSessionBean() { + protected void onEjbCreate() throws CreateException { + assertTrue(getBeanFactory() == bf); + } + }; + // Must call this method before ejbCreate() + slsb.setBeanFactoryLocator(bfl); + slsb.setSessionContext(sc); + assertTrue(sc == slsb.getSessionContext()); + slsb.ejbCreate(); + try { + slsb.ejbActivate(); + fail("Shouldn't allow activation of SLSB"); + } + catch (IllegalStateException ex) { + // Ok + } + try { + slsb.ejbPassivate(); + fail("Shouldn't allow passivation of SLSB"); + } + catch (IllegalStateException ex) { + // Ok + } + } + + public void testJmsMdb() throws Exception { + MockControl mc = MockControl.createControl(MessageDrivenContext.class); + MessageDrivenContext sc = (MessageDrivenContext) mc.getMock(); + mc.replay(); + + final BeanFactory bf = new StaticListableBeanFactory(); + BeanFactoryLocator bfl = new BeanFactoryLocator() { + public BeanFactoryReference useBeanFactory(String factoryKey) throws FatalBeanException { + return new BeanFactoryReference() { + public BeanFactory getFactory() { + return bf; + } + public void release() throws FatalBeanException { + // nothing to do in default implementation + } + }; + } + }; + + AbstractJmsMessageDrivenBean mdb = new AbstractJmsMessageDrivenBean() { + protected void onEjbCreate() { + assertTrue(getBeanFactory() == bf); + } + public void onMessage(Message msg) { + throw new UnsupportedOperationException("onMessage"); + } + }; + // Must call this method before ejbCreate() + mdb.setBeanFactoryLocator(bfl); + mdb.setMessageDrivenContext(sc); + assertTrue(sc == mdb.getMessageDrivenContext()); + mdb.ejbCreate(); + } + + public void testCannotLoadBeanFactory() throws Exception { + MockControl mc = MockControl.createControl(SessionContext.class); + SessionContext sc = (SessionContext) mc.getMock(); + mc.replay(); + + BeanFactoryLocator bfl = new BeanFactoryLocator() { + public BeanFactoryReference useBeanFactory(String factoryKey) throws FatalBeanException { + throw new BootstrapException("", null); + }}; + + AbstractStatelessSessionBean slsb = new AbstractStatelessSessionBean() { + protected void onEjbCreate() throws CreateException { + } + }; + // Must call this method before ejbCreate() + slsb.setBeanFactoryLocator(bfl); + slsb.setSessionContext(sc); + + try { + slsb.ejbCreate(); + fail(); + } + catch (BeansException ex) { + // Ok + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/InstrumentableClassLoaderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/InstrumentableClassLoaderTests.java new file mode 100644 index 00000000000..32c2f04d3a0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/InstrumentableClassLoaderTests.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2006 the original author 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.instrument.classloading; + +import junit.framework.TestCase; + +import org.springframework.util.ClassUtils; + +/** + * @author Costin Leau + * @author Juergen Hoeller + */ +public class InstrumentableClassLoaderTests extends TestCase { + + public void testDefaultLoadTimeWeaver() { + ClassLoader loader = new SimpleInstrumentableClassLoader(ClassUtils.getDefaultClassLoader()); + ReflectiveLoadTimeWeaver handler = new ReflectiveLoadTimeWeaver(loader); + assertSame(loader, handler.getInstrumentableClassLoader()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/ReflectiveLoadTimeWeaverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/ReflectiveLoadTimeWeaverTests.java new file mode 100644 index 00000000000..8c367c94453 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/ReflectiveLoadTimeWeaverTests.java @@ -0,0 +1,116 @@ +/* + * Copyright 2002-2006 the original author 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.instrument.classloading; + +import junit.framework.TestCase; +import org.springframework.test.AssertThrows; + +import java.lang.instrument.ClassFileTransformer; +import java.security.ProtectionDomain; + +/** + * Unit tests for the {@link ReflectiveLoadTimeWeaver} class. + * + * @author Rick Evans + */ +public final class ReflectiveLoadTimeWeaverTests extends TestCase { + + public void testCtorWithNullClassLoader() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new ReflectiveLoadTimeWeaver(null); + } + }.runTest(); + } + + public void testCtorWithClassLoaderThatDoesNotExposeAnAddTransformerMethod() throws Exception { + new AssertThrows(IllegalStateException.class) { + public void test() throws Exception { + new ReflectiveLoadTimeWeaver(getClass().getClassLoader()); + } + }.runTest(); + } + + public void testCtorWithClassLoaderThatDoesNotExposeAGetThrowawayClassLoaderMethodIsOkay() throws Exception { + JustAddTransformerClassLoader classLoader = new JustAddTransformerClassLoader(); + ReflectiveLoadTimeWeaver weaver = new ReflectiveLoadTimeWeaver(classLoader); + weaver.addTransformer(new ClassFileTransformer() { + public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { + return "CAFEDEAD".getBytes(); + } + }); + assertEquals(1, classLoader.getNumTimesGetThrowawayClassLoaderCalled()); + } + + public void testAddTransformerWithNullTransformer() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new ReflectiveLoadTimeWeaver(new JustAddTransformerClassLoader()).addTransformer(null); + } + }.runTest(); + } + + public void testGetThrowawayClassLoaderWithClassLoaderThatDoesNotExposeAGetThrowawayClassLoaderMethodYieldsFallbackClassLoader() throws Exception { + ReflectiveLoadTimeWeaver weaver = new ReflectiveLoadTimeWeaver(new JustAddTransformerClassLoader()); + ClassLoader throwawayClassLoader = weaver.getThrowawayClassLoader(); + assertNotNull(throwawayClassLoader); + } + + public void testGetThrowawayClassLoaderWithTotallyCompliantClassLoader() throws Exception { + TotallyCompliantClassLoader classLoader = new TotallyCompliantClassLoader(); + ReflectiveLoadTimeWeaver weaver = new ReflectiveLoadTimeWeaver(classLoader); + ClassLoader throwawayClassLoader = weaver.getThrowawayClassLoader(); + assertNotNull(throwawayClassLoader); + assertEquals(1, classLoader.getNumTimesGetThrowawayClassLoaderCalled()); + } + + + public static class JustAddTransformerClassLoader extends ClassLoader { + + private int numTimesAddTransformerCalled = 0; + + + public int getNumTimesGetThrowawayClassLoaderCalled() { + return this.numTimesAddTransformerCalled; + } + + + public void addTransformer(ClassFileTransformer transformer) { + ++this.numTimesAddTransformerCalled; + } + + } + + + public static final class TotallyCompliantClassLoader extends JustAddTransformerClassLoader { + + private int numTimesGetThrowawayClassLoaderCalled = 0; + + + public int getNumTimesGetThrowawayClassLoaderCalled() { + return this.numTimesGetThrowawayClassLoaderCalled; + } + + + public ClassLoader getThrowawayClassLoader() { + ++this.numTimesGetThrowawayClassLoaderCalled; + return getClass().getClassLoader(); + } + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/ResourceOverridingShadowingClassLoaderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/ResourceOverridingShadowingClassLoaderTests.java new file mode 100644 index 00000000000..8a49d91ef9a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/ResourceOverridingShadowingClassLoaderTests.java @@ -0,0 +1,79 @@ +/* + * Copyright 2002-2006 the original author 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.instrument.classloading; + +import java.io.IOException; +import java.util.Enumeration; + +import junit.framework.TestCase; + +/** + * @author Rod Johnson + * @since 2.0 + */ +public class ResourceOverridingShadowingClassLoaderTests extends TestCase { + + private static final String EXISTING_RESOURCE = "org/springframework/instrument/classloading/testResource.xml"; + + private ClassLoader thisClassLoader = getClass().getClassLoader(); + + private ResourceOverridingShadowingClassLoader overridingLoader = new ResourceOverridingShadowingClassLoader(thisClassLoader); + + + public void testFindsExistingResourceWithGetResourceAndNoOverrides() { + assertNotNull(thisClassLoader.getResource(EXISTING_RESOURCE)); + assertNotNull(overridingLoader.getResource(EXISTING_RESOURCE)); + } + + public void testDoesNotFindExistingResourceWithGetResourceAndNullOverride() { + assertNotNull(thisClassLoader.getResource(EXISTING_RESOURCE)); + overridingLoader.override(EXISTING_RESOURCE, null); + assertNull(overridingLoader.getResource(EXISTING_RESOURCE)); + } + + public void testFindsExistingResourceWithGetResourceAsStreamAndNoOverrides() { + assertNotNull(thisClassLoader.getResourceAsStream(EXISTING_RESOURCE)); + assertNotNull(overridingLoader.getResourceAsStream(EXISTING_RESOURCE)); + } + + public void testDoesNotFindExistingResourceWithGetResourceAsStreamAndNullOverride() { + assertNotNull(thisClassLoader.getResourceAsStream(EXISTING_RESOURCE)); + overridingLoader.override(EXISTING_RESOURCE, null); + assertNull(overridingLoader.getResourceAsStream(EXISTING_RESOURCE)); + } + + public void testFindsExistingResourceWithGetResourcesAndNoOverrides() throws IOException { + assertNotNull(thisClassLoader.getResources(EXISTING_RESOURCE)); + assertNotNull(overridingLoader.getResources(EXISTING_RESOURCE)); + assertEquals(1, countElements(overridingLoader.getResources(EXISTING_RESOURCE))); + } + + public void testDoesNotFindExistingResourceWithGetResourcesAndNullOverride() throws IOException { + assertNotNull(thisClassLoader.getResources(EXISTING_RESOURCE)); + overridingLoader.override(EXISTING_RESOURCE, null); + assertEquals(0, countElements(overridingLoader.getResources(EXISTING_RESOURCE))); + } + + private int countElements(Enumeration e) { + int elts = 0; + while (e.hasMoreElements()) { + e.nextElement(); + ++elts; + } + return elts; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/glassfish/GlassFishLoadTimeWeaverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/glassfish/GlassFishLoadTimeWeaverTests.java new file mode 100644 index 00000000000..48cb0c14427 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/glassfish/GlassFishLoadTimeWeaverTests.java @@ -0,0 +1,153 @@ +/* + * Copyright 2002-2006 the original author 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.instrument.classloading.glassfish; + +import java.lang.instrument.ClassFileTransformer; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.SecureClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.persistence.spi.ClassTransformer; + +import com.sun.enterprise.loader.InstrumentableClassLoader; +import junit.framework.TestCase; +import org.easymock.ArgumentsMatcher; +import org.easymock.MockControl; + +import org.springframework.instrument.classloading.LoadTimeWeaver; + +public class GlassFishLoadTimeWeaverTests extends TestCase { + + private MockControl loaderCtrl; + private InstrumentableClassLoader loader; + private LoadTimeWeaver ltw; + + private class DummyInstrumentableClassLoader extends SecureClassLoader implements InstrumentableClassLoader { + + public DummyInstrumentableClassLoader() { + super(); + } + + public DummyInstrumentableClassLoader(ClassLoader parent) { + super(parent); + } + + private List transformers = new ArrayList(); + + public void addTransformer(ClassTransformer transformer) { + transformers.add(transformer); + } + + public ClassLoader copy() { + return new DummyInstrumentableClassLoader(); + } + } + + protected void setUp() throws Exception { + loaderCtrl = MockControl.createControl(InstrumentableClassLoader.class); + loader = (InstrumentableClassLoader) loaderCtrl.getMock(); + loaderCtrl.replay(); + + ltw = new GlassFishLoadTimeWeaver() { + @Override + protected InstrumentableClassLoader determineClassLoader(ClassLoader cl) { + return loader; + } + }; + } + + protected void tearDown() throws Exception { + loaderCtrl.verify(); + ltw = null; + } + + public void testGlassFishLoadTimeWeaver() { + try { + ltw = new GlassFishLoadTimeWeaver(); + fail("expected exception"); + } + catch (IllegalArgumentException ex) { + // expected + } + + } + + public void testGlassFishLoadTimeWeaverClassLoader() { + try { + ltw = new GlassFishLoadTimeWeaver(null); + fail("expected exception"); + } + catch (RuntimeException e) { + // expected + } + + ClassLoader cl1 = new URLClassLoader(new URL[0]); + ClassLoader cl2 = new URLClassLoader(new URL[0], cl1); + ClassLoader cl3 = new DummyInstrumentableClassLoader(cl2); + ClassLoader cl4 = new URLClassLoader(new URL[0], cl3); + + ltw = new GlassFishLoadTimeWeaver(cl4); + assertSame(cl3, ltw.getInstrumentableClassLoader()); + + cl1 = new URLClassLoader(new URL[0]); + cl2 = new URLClassLoader(new URL[0], cl1); + cl3 = new DummyInstrumentableClassLoader(cl2); + cl4 = new DummyInstrumentableClassLoader(cl3); + + ltw = new GlassFishLoadTimeWeaver(cl4); + assertSame(cl4, ltw.getInstrumentableClassLoader()); + } + + public void testAddTransformer() { + ClassFileTransformer transformer = (ClassFileTransformer) MockControl.createNiceControl( + ClassFileTransformer.class).getMock(); + loaderCtrl.reset(); + loader.addTransformer(new ClassTransformerAdapter(transformer)); + loaderCtrl.setMatcher(new ArgumentsMatcher() { + + public boolean matches(Object[] arg0, Object[] arg1) { + for (int i = 0; i < arg0.length; i++) { + if (arg0 != null && arg0.getClass() != arg1.getClass()) + return false; + } + return true; + } + + public String toString(Object[] arg0) { + return Arrays.toString(arg0); + } + + }); + + loaderCtrl.replay(); + + ltw.addTransformer(transformer); + } + + public void testGetThrowawayClassLoader() { + loaderCtrl.reset(); + ClassLoader cl = new URLClassLoader(new URL[0]); + loaderCtrl.expectAndReturn(loader.copy(), cl); + loaderCtrl.replay(); + + assertSame(ltw.getThrowawayClassLoader(), cl); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/oc4j/OC4JClassPreprocessorAdapterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/oc4j/OC4JClassPreprocessorAdapterTests.java new file mode 100644 index 00000000000..0dd77d8efb6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/oc4j/OC4JClassPreprocessorAdapterTests.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2006 the original author 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.instrument.classloading.oc4j; + +import junit.framework.TestCase; +import org.easymock.AbstractMatcher; +import org.easymock.MockControl; +import org.springframework.test.AssertThrows; + +import java.lang.instrument.ClassFileTransformer; + +/** + * Unit tests for the {@link OC4JClassPreprocessorAdapter} class. + * + * @author Rick Evans + */ +public final class OC4JClassPreprocessorAdapterTests extends TestCase { + + public void testClassNameIsUnMangledPriorToTransformation() throws Exception { + final byte[] classBytes = "CAFEBABE".getBytes(); + final ClassLoader classLoader = getClass().getClassLoader(); + + MockControl mockTransformer = MockControl.createControl(ClassFileTransformer.class); + ClassFileTransformer transformer = (ClassFileTransformer) mockTransformer.getMock(); + + transformer.transform(classLoader, "com/foo/Bar", null, null, classBytes); + mockTransformer.setMatcher(new AbstractMatcher() { + public boolean matches(Object[] expected, Object[] actual) { + return expected[1].equals(actual[1]); + } + }); + mockTransformer.setReturnValue(classBytes); + + mockTransformer.replay(); + + OC4JClassPreprocessorAdapter processor = new OC4JClassPreprocessorAdapter(transformer); + byte[] bytes = processor.processClass("com.foo.Bar", classBytes, 0, 0, null, classLoader); + assertNotNull(bytes); + + mockTransformer.verify(); + } + + public void testCtorWithNullClassFileTransformer() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new OC4JClassPreprocessorAdapter(null); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/oc4j/OC4JLoadTimeWeaverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/oc4j/OC4JLoadTimeWeaverTests.java new file mode 100644 index 00000000000..7b93287e2bb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/oc4j/OC4JLoadTimeWeaverTests.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2006 the original author 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.instrument.classloading.oc4j; + +import junit.framework.TestCase; +import org.springframework.test.AssertThrows; + +/** + * Unit tests for the {@link OC4JLoadTimeWeaver} class. + * + * @author Rick Evans + */ +public final class OC4JLoadTimeWeaverTests extends TestCase { + + public void testCtorWithNullClassLoader() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new OC4JLoadTimeWeaver(null); + } + }.runTest(); + } + + public void testAddTransformerWithNullTransformer() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new OC4JLoadTimeWeaver().addTransformer(null); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/testResource.xml b/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/testResource.xml new file mode 100644 index 00000000000..9de559da804 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/instrument/classloading/testResource.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/CallMetaDataContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/CallMetaDataContextTests.java new file mode 100644 index 00000000000..6ca38bd21f0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/CallMetaDataContextTests.java @@ -0,0 +1,114 @@ +package org.springframework.jdbc.core.simple; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.springframework.jdbc.core.metadata.CallMetaDataContext; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.SqlParameter; +import org.springframework.jdbc.core.SqlOutParameter; +import org.springframework.jdbc.core.SqlInOutParameter; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.Types; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Mock object based tests for CallMetaDataContext. + * + * @author Thomas Risberg + */ +public class CallMetaDataContextTests extends TestCase { + private MockControl ctrlDataSource; + private DataSource mockDataSource; + private MockControl ctrlConnection; + private Connection mockConnection; + private MockControl ctrlDatabaseMetaData; + private DatabaseMetaData mockDatabaseMetaData; + + private CallMetaDataContext context = new CallMetaDataContext(); + + protected void setUp() throws Exception { + super.setUp(); + + ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + + ctrlConnection = MockControl.createControl(Connection.class); + mockConnection = (Connection) ctrlConnection.getMock(); + mockConnection.getMetaData(); + ctrlConnection.setDefaultReturnValue(mockDatabaseMetaData); + mockConnection.close(); + ctrlConnection.setDefaultVoidCallable(); + + ctrlDataSource = MockControl.createControl(DataSource.class); + mockDataSource = (DataSource) ctrlDataSource.getMock(); + mockDataSource.getConnection(); + ctrlDataSource.setDefaultReturnValue(mockConnection); + + } + + protected void tearDown() throws Exception { + super.tearDown(); + ctrlDatabaseMetaData.verify(); + ctrlDataSource.verify(); + } + + protected void replay() { + ctrlDatabaseMetaData.replay(); + ctrlConnection.replay(); + ctrlDataSource.replay(); + } + + public void testMatchParameterValuesAndSqlInOutParameters() throws Exception { + final String TABLE = "customers"; + final String USER = "me"; + + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MyDB"); + mockDatabaseMetaData.supportsCatalogsInProcedureCalls(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.supportsSchemasInProcedureCalls(); + ctrlDatabaseMetaData.setReturnValue(false); + + mockDatabaseMetaData.getUserName(); + ctrlDatabaseMetaData.setReturnValue(USER); + mockDatabaseMetaData.storesUpperCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.storesLowerCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(true); + + replay(); + + List parameters = new ArrayList(); + parameters.add(new SqlParameter("id", Types.NUMERIC)); + parameters.add(new SqlInOutParameter("name", Types.NUMERIC)); + parameters.add(new SqlOutParameter("customer_no", Types.NUMERIC)); + + MapSqlParameterSource parameterSource = new MapSqlParameterSource(); + parameterSource.addValue("id", 1); + parameterSource.addValue("name", "Sven"); + parameterSource.addValue("customer_no", "12345XYZ"); + + context.setProcedureName(TABLE); + context.initializeMetaData(mockDataSource); + context.processParameters(parameters); + + Map inParameters = context.matchInParameterValuesWithCallParameters(parameterSource); + assertEquals("Wrong number of matched in parameter values", 2, inParameters.size()); + assertTrue("in parameter value missing", inParameters.containsKey("id")); + assertTrue("in out parameter value missing", inParameters.containsKey("name")); + assertTrue("out parameter value matched", !inParameters.containsKey("customer_no")); + + List names = context.getOutParameterNames(); + assertEquals("Wrong number of out parameters", 2, names.size()); + + List callParameters = context.getCallParameters(); + assertEquals("Wrong number of call parameters", 3, callParameters.size()); + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/ParameterizedBeanPropertyRowMapperTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/ParameterizedBeanPropertyRowMapperTests.java new file mode 100644 index 00000000000..64bca82610d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/ParameterizedBeanPropertyRowMapperTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.simple; + +import java.sql.SQLException; +import java.util.List; + +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.jdbc.core.AbstractRowMapperTests; +import org.springframework.jdbc.core.test.ConcretePerson; +import org.springframework.jdbc.core.test.Person; + +/** + * @author Thomas Risberg + */ +public class ParameterizedBeanPropertyRowMapperTests extends AbstractRowMapperTests { + + private SimpleJdbcTemplate simpleJdbcTemplate; + + protected void setUp() throws SQLException { + super.setUp(); + simpleJdbcTemplate = new SimpleJdbcTemplate(jdbcTemplate); + } + + public void testOverridingClassDefinedForMapping() { + ParameterizedBeanPropertyRowMapper mapper = + ParameterizedBeanPropertyRowMapper.newInstance(Person.class); + try { + ((ParameterizedBeanPropertyRowMapper) mapper).setMappedClass(Long.class); + fail("Setting new class should have thrown InvalidDataAccessApiUsageException"); + } + catch (InvalidDataAccessApiUsageException ex) { + // expected + } + try { + mapper.setMappedClass(Person.class); + } + catch (InvalidDataAccessApiUsageException ex) { + fail("Setting same class should not have thrown InvalidDataAccessApiUsageException"); + } + } + + public void testStaticQueryWithRowMapper() throws SQLException { + List result = simpleJdbcTemplate.query("select name, age, birth_date, balance from people", + ParameterizedBeanPropertyRowMapper.newInstance(Person.class)); + assertEquals(1, result.size()); + Person bean = result.get(0); + verifyPerson(bean); + } + + public void testMappingWithInheritance() throws SQLException { + List result = simpleJdbcTemplate.query("select name, age, birth_date, balance from people", + ParameterizedBeanPropertyRowMapper.newInstance(ConcretePerson.class)); + assertEquals(1, result.size()); + ConcretePerson bean = result.get(0); + verifyConcretePerson(bean); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/SimpleJdbcCallTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/SimpleJdbcCallTests.java new file mode 100644 index 00000000000..03d0315eb2a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/SimpleJdbcCallTests.java @@ -0,0 +1,469 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.simple; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.apache.commons.logging.LogFactory; + +import org.springframework.jdbc.BadSqlGrammarException; +import org.springframework.jdbc.core.SqlOutParameter; +import org.springframework.jdbc.core.SqlParameter; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.simple.SimpleJdbcCall; +import org.springframework.dao.InvalidDataAccessApiUsageException; + +import javax.sql.DataSource; +import java.sql.*; + +/** + * Mock object based tests for SimpleJdbcCall. + * + * @author Thomas Risberg + */ +public class SimpleJdbcCallTests extends TestCase { + + private final boolean debugEnabled = LogFactory.getLog(JdbcTemplate.class).isDebugEnabled(); + + private MockControl ctrlDataSource; + private DataSource mockDataSource; + private MockControl ctrlConnection; + private Connection mockConnection; + private MockControl ctrlDatabaseMetaData; + private DatabaseMetaData mockDatabaseMetaData; + private MockControl ctrlCallable; + private CallableStatement mockCallable; + + protected void setUp() throws Exception { + ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + + ctrlConnection = MockControl.createControl(Connection.class); + mockConnection = (Connection) ctrlConnection.getMock(); + mockConnection.getMetaData(); + ctrlConnection.setDefaultReturnValue(mockDatabaseMetaData); + mockConnection.close(); + ctrlConnection.setDefaultVoidCallable(); + + ctrlDataSource = MockControl.createControl(DataSource.class); + mockDataSource = (DataSource) ctrlDataSource.getMock(); + mockDataSource.getConnection(); + ctrlDataSource.setDefaultReturnValue(mockConnection); + + ctrlCallable = MockControl.createControl(CallableStatement.class); + mockCallable = (CallableStatement) ctrlCallable.getMock(); + } + + protected void tearDown() throws Exception { + ctrlDatabaseMetaData.verify(); + ctrlDataSource.verify(); + ctrlCallable.verify(); + } + + protected void replay() { + ctrlDatabaseMetaData.replay(); + ctrlConnection.replay(); + ctrlDataSource.replay(); + ctrlCallable.replay(); + } + + public void testNoSuchStoredProcedure() throws Exception { + final String NO_SUCH_PROC = "x"; + + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MyDB"); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MyDB"); + mockDatabaseMetaData.getUserName(); + ctrlDatabaseMetaData.setReturnValue("me"); + mockDatabaseMetaData.supportsCatalogsInProcedureCalls(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.supportsSchemasInProcedureCalls(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.storesUpperCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.storesLowerCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(true); + + SQLException sex = + new SQLException( + "Syntax error or access violation exception", + "42000"); + mockCallable.execute(); + ctrlCallable.setThrowable(sex); + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall( + "{call " + NO_SUCH_PROC + "()}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + + SimpleJdbcCall sproc = new SimpleJdbcCall(mockDataSource).withProcedureName(NO_SUCH_PROC); + try { + sproc.execute(); + fail("Shouldn't succeed in running stored procedure which doesn't exist"); + } catch (BadSqlGrammarException ex) { + // OK + } + } + + public void testUnnamedParameterHandling() throws Exception { + final String MY_PROC = "my_proc"; + + replay(); + + SimpleJdbcCall sproc = new SimpleJdbcCall(mockDataSource).withProcedureName(MY_PROC); + try { + sproc.addDeclaredParameter(new SqlParameter(1)); + fail("Shouldn't succeed in adding unnamed parameter"); + } catch (InvalidDataAccessApiUsageException ex) { + // OK + } + } + + public void testAddInvoiceProcWithoutMetaData() throws Exception { + final int amount = 1103; + final int custid = 3; + + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MyDB"); + mockDatabaseMetaData.getUserName(); + ctrlDatabaseMetaData.setReturnValue("me"); + mockDatabaseMetaData.supportsCatalogsInProcedureCalls(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.supportsSchemasInProcedureCalls(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.storesUpperCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.storesLowerCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(true); + + mockCallable.setObject(1, 1103, 4); + ctrlCallable.setVoidCallable(); + mockCallable.setObject(2, 3, 4); + ctrlCallable.setVoidCallable(); + mockCallable.registerOutParameter(3, 4); + ctrlCallable.setVoidCallable(); + mockCallable.execute(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getObject(3); + ctrlCallable.setReturnValue(new Long(4)); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall( + "{call add_invoice(?, ?, ?)}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + + SimpleJdbcCall adder = new SimpleJdbcCall(mockDataSource).withProcedureName("add_invoice"); + adder.declareParameters(new SqlParameter("amount", Types.INTEGER), + new SqlParameter("custid", Types.INTEGER), + new SqlOutParameter("newid", Types.INTEGER)); + Number newId = adder.executeObject(Number.class, new MapSqlParameterSource() + .addValue("amount", amount) + .addValue("custid", custid)); + assertEquals(4, newId.intValue()); + } + + public void testAddInvoiceProcWithMetaData() throws Exception { + final int amount = 1103; + final int custid = 3; + + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString("PROCEDURE_CAT"); + ctrlResultSet.setReturnValue(null); + mockResultSet.getString("PROCEDURE_SCHEM"); + ctrlResultSet.setReturnValue(null); + mockResultSet.getString("PROCEDURE_NAME"); + ctrlResultSet.setReturnValue("add_invoice"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString("COLUMN_NAME"); + ctrlResultSet.setReturnValue("amount"); + mockResultSet.getInt("COLUMN_TYPE"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getInt("DATA_TYPE"); + ctrlResultSet.setReturnValue(4); + mockResultSet.getString("TYPE_NAME"); + ctrlResultSet.setReturnValue(null); + mockResultSet.getBoolean("NULLABLE"); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString("COLUMN_NAME"); + ctrlResultSet.setReturnValue("custid"); + mockResultSet.getInt("COLUMN_TYPE"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getInt("DATA_TYPE"); + ctrlResultSet.setReturnValue(4); + mockResultSet.getString("TYPE_NAME"); + ctrlResultSet.setReturnValue(null); + mockResultSet.getBoolean("NULLABLE"); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString("COLUMN_NAME"); + ctrlResultSet.setReturnValue("newid"); + mockResultSet.getInt("COLUMN_TYPE"); + ctrlResultSet.setReturnValue(4); + mockResultSet.getInt("DATA_TYPE"); + ctrlResultSet.setReturnValue(4); + mockResultSet.getString("TYPE_NAME"); + ctrlResultSet.setReturnValue(null); + mockResultSet.getBoolean("NULLABLE"); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("Oracle"); + mockDatabaseMetaData.getUserName(); + ctrlDatabaseMetaData.setReturnValue("ME"); + mockDatabaseMetaData.supportsCatalogsInProcedureCalls(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.supportsSchemasInProcedureCalls(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.storesUpperCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(true); + mockDatabaseMetaData.storesLowerCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.getProcedures("", "ME", "ADD_INVOICE"); + ctrlDatabaseMetaData.setReturnValue(mockResultSet); + mockDatabaseMetaData.getProcedureColumns("", "ME", "ADD_INVOICE", null); + ctrlDatabaseMetaData.setReturnValue(mockResultSet); + + mockCallable.setObject(1, 1103, 4); + ctrlCallable.setVoidCallable(); + mockCallable.setObject(2, 3, 4); + ctrlCallable.setVoidCallable(); + mockCallable.registerOutParameter(3, 4); + ctrlCallable.setVoidCallable(); + mockCallable.execute(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getObject(3); + ctrlCallable.setReturnValue(new Long(4)); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall( + "{call ADD_INVOICE(?, ?, ?)}"); + ctrlConnection.setReturnValue(mockCallable); + + ctrlResultSet.replay(); + replay(); + + SimpleJdbcCall adder = new SimpleJdbcCall(mockDataSource).withProcedureName("add_invoice"); + Number newId = adder.executeObject(Number.class, new MapSqlParameterSource() + .addValue("amount", amount) + .addValue("custid", custid)); + assertEquals(4, newId.intValue()); + + ctrlResultSet.verify(); + } + + public void testAddInvoiceFuncWithoutMetaData() throws Exception { + final int amount = 1103; + final int custid = 3; + + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MyDB"); + mockDatabaseMetaData.getUserName(); + ctrlDatabaseMetaData.setReturnValue("me"); + mockDatabaseMetaData.supportsCatalogsInProcedureCalls(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.supportsSchemasInProcedureCalls(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.storesUpperCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.storesLowerCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(true); + + mockCallable.registerOutParameter(1, 4); + ctrlCallable.setVoidCallable(); + mockCallable.setObject(2, 1103, 4); + ctrlCallable.setVoidCallable(); + mockCallable.setObject(3, 3, 4); + ctrlCallable.setVoidCallable(); + mockCallable.execute(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getObject(1); + ctrlCallable.setReturnValue(new Long(4)); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall( + "{? = call add_invoice(?, ?)}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + + SimpleJdbcCall adder = new SimpleJdbcCall(mockDataSource).withFunctionName("add_invoice"); + adder.declareParameters(new SqlOutParameter("return", Types.INTEGER), + new SqlParameter("amount", Types.INTEGER), + new SqlParameter("custid", Types.INTEGER)); + Number newId = adder.executeFunction(Number.class, new MapSqlParameterSource() + .addValue("amount", amount) + .addValue("custid", custid)); + assertEquals(4, newId.intValue()); + } + + public void testAddInvoiceFuncWithMetaData() throws Exception { + final int amount = 1103; + final int custid = 3; + + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString("PROCEDURE_CAT"); + ctrlResultSet.setReturnValue(null); + mockResultSet.getString("PROCEDURE_SCHEM"); + ctrlResultSet.setReturnValue(null); + mockResultSet.getString("PROCEDURE_NAME"); + ctrlResultSet.setReturnValue("add_invoice"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString("COLUMN_NAME"); + ctrlResultSet.setReturnValue(null); + mockResultSet.getInt("COLUMN_TYPE"); + ctrlResultSet.setReturnValue(5); + mockResultSet.getInt("DATA_TYPE"); + ctrlResultSet.setReturnValue(4); + mockResultSet.getString("TYPE_NAME"); + ctrlResultSet.setReturnValue(null); + mockResultSet.getBoolean("NULLABLE"); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString("COLUMN_NAME"); + ctrlResultSet.setReturnValue("amount"); + mockResultSet.getInt("COLUMN_TYPE"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getInt("DATA_TYPE"); + ctrlResultSet.setReturnValue(4); + mockResultSet.getString("TYPE_NAME"); + ctrlResultSet.setReturnValue(null); + mockResultSet.getBoolean("NULLABLE"); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString("COLUMN_NAME"); + ctrlResultSet.setReturnValue("custid"); + mockResultSet.getInt("COLUMN_TYPE"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getInt("DATA_TYPE"); + ctrlResultSet.setReturnValue(4); + mockResultSet.getString("TYPE_NAME"); + ctrlResultSet.setReturnValue(null); + mockResultSet.getBoolean("NULLABLE"); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("Oracle"); + mockDatabaseMetaData.getUserName(); + ctrlDatabaseMetaData.setReturnValue("ME"); + mockDatabaseMetaData.supportsCatalogsInProcedureCalls(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.supportsSchemasInProcedureCalls(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.storesUpperCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(true); + mockDatabaseMetaData.storesLowerCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.getProcedures("", "ME", "ADD_INVOICE"); + ctrlDatabaseMetaData.setReturnValue(mockResultSet); + mockDatabaseMetaData.getProcedureColumns("", "ME", "ADD_INVOICE", null); + ctrlDatabaseMetaData.setReturnValue(mockResultSet); + + mockCallable.registerOutParameter(1, 4); + ctrlCallable.setVoidCallable(); + mockCallable.setObject(2, 1103, 4); + ctrlCallable.setVoidCallable(); + mockCallable.setObject(3, 3, 4); + ctrlCallable.setVoidCallable(); + mockCallable.execute(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getObject(1); + ctrlCallable.setReturnValue(new Long(4)); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall( + "{? = call ADD_INVOICE(?, ?)}"); + ctrlConnection.setReturnValue(mockCallable); + + ctrlResultSet.replay(); + replay(); + + SimpleJdbcCall adder = new SimpleJdbcCall(mockDataSource).withFunctionName("add_invoice"); + Number newId = adder.executeFunction(Number.class, new MapSqlParameterSource() + .addValue("amount", amount) + .addValue("custid", custid)); + assertEquals(4, newId.intValue()); + + ctrlResultSet.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/SimpleJdbcInsertTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/SimpleJdbcInsertTests.java new file mode 100644 index 00000000000..7d7b47918e1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/SimpleJdbcInsertTests.java @@ -0,0 +1,118 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.simple; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.springframework.dao.InvalidDataAccessApiUsageException; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.util.HashMap; + +/** + * Mock object based tests for SimpleJdbcInsert. + * + * @author Thomas Risberg + */ +public class SimpleJdbcInsertTests extends TestCase { + + private MockControl ctrlDataSource; + private DataSource mockDataSource; + private MockControl ctrlConnection; + private Connection mockConnection; + private MockControl ctrlDatabaseMetaData; + private DatabaseMetaData mockDatabaseMetaData; + + protected void setUp() throws Exception { + super.setUp(); + + ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + + ctrlConnection = MockControl.createControl(Connection.class); + mockConnection = (Connection) ctrlConnection.getMock(); + mockConnection.getMetaData(); + ctrlConnection.setDefaultReturnValue(mockDatabaseMetaData); + mockConnection.close(); + ctrlConnection.setDefaultVoidCallable(); + + ctrlDataSource = MockControl.createControl(DataSource.class); + mockDataSource = (DataSource) ctrlDataSource.getMock(); + mockDataSource.getConnection(); + ctrlDataSource.setDefaultReturnValue(mockConnection); + + } + + protected void tearDown() throws Exception { + super.tearDown(); + ctrlDatabaseMetaData.verify(); + ctrlDataSource.verify(); + } + + protected void replay() { + ctrlDatabaseMetaData.replay(); + ctrlConnection.replay(); + ctrlDataSource.replay(); + } + + public void testNoSuchTable() throws Exception { + final String NO_SUCH_TABLE = "x"; + final String USER = "me"; + + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MyDB"); + mockDatabaseMetaData.supportsGetGeneratedKeys(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MyDB"); + mockDatabaseMetaData.getDatabaseProductVersion(); + ctrlDatabaseMetaData.setReturnValue("1.0"); + mockDatabaseMetaData.getUserName(); + ctrlDatabaseMetaData.setReturnValue(USER); + mockDatabaseMetaData.storesUpperCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.storesLowerCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(true); + mockDatabaseMetaData.getTables(null, null, NO_SUCH_TABLE, null); + ctrlDatabaseMetaData.setReturnValue(mockResultSet); + + ctrlResultSet.replay(); + replay(); + + SimpleJdbcInsert insert = new SimpleJdbcInsert(mockDataSource).withTableName(NO_SUCH_TABLE); + try { + insert.execute(new HashMap()); + fail("Shouldn't succeed in inserting into table which doesn't exist"); + } catch (InvalidDataAccessApiUsageException ex) { + // OK + } + } + + public void testInsert() throws Exception { + replay(); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/SimpleJdbcTemplateTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/SimpleJdbcTemplateTests.java new file mode 100644 index 00000000000..58c58766d2f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/SimpleJdbcTemplateTests.java @@ -0,0 +1,677 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.simple; + +import java.lang.reflect.Method; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.easymock.internal.ArrayMatcher; +import org.apache.commons.logging.LogFactory; + +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; +import org.springframework.jdbc.core.namedparam.SqlParameterSource; + +/** + * @author Rod Johnson + * @author Rob Harrop + * @author Juergen Hoeller + * @author Thomas Risberg + */ +public class SimpleJdbcTemplateTests extends TestCase { + + private final boolean debugEnabled = LogFactory.getLog(JdbcTemplate.class).isDebugEnabled(); + + + public void testQueryForIntWithoutArgs() { + String sql = "SELECT COUNT(0) FROM BAR"; + int expectedResult = 666; + + MockControl mc = MockControl.createControl(JdbcOperations.class); + JdbcOperations jo = (JdbcOperations) mc.getMock(); + jo.queryForInt(sql); + mc.setReturnValue(expectedResult); + mc.replay(); + + SimpleJdbcTemplate jth = new SimpleJdbcTemplate(jo); + + assertSame(jo, jth.getJdbcOperations()); + + int result = jth.queryForInt(sql); + assertEquals(expectedResult, result); + + mc.verify(); + } + + public void testQueryForIntWithArgs() { + String sql = "SELECT COUNT(0) FROM BAR WHERE ID=? AND XY=?"; + int expectedResult = 666; + int arg1 = 24; + String arg2 = "foo"; + + MockControl mc = MockControl.createControl(JdbcOperations.class); + JdbcOperations jo = (JdbcOperations) mc.getMock(); + jo.queryForInt(sql, new Object[]{arg1, arg2}); + mc.setDefaultMatcher(new ArrayMatcher()); + mc.setReturnValue(expectedResult); + mc.replay(); + + SimpleJdbcTemplate jth = new SimpleJdbcTemplate(jo); + int result = jth.queryForInt(sql, arg1, arg2); + assertEquals(expectedResult, result); + mc.verify(); + } + + public void testQueryForIntWithMap() { + String sql = "SELECT COUNT(0) FROM BAR WHERE ID=:id AND XY=:xy"; + int expectedResult = 666; + int arg1 = 24; + String arg2 = "foo"; + + MockControl mc = MockControl.createControl(NamedParameterJdbcOperations.class); + NamedParameterJdbcOperations npjo = (NamedParameterJdbcOperations) mc.getMock(); + Map args = new HashMap(2); + args.put("id", arg1); + args.put("xy", arg2); + npjo.queryForInt(sql, args); + mc.setDefaultMatcher(new ArrayMatcher()); + mc.setReturnValue(expectedResult); + mc.replay(); + + SimpleJdbcTemplate jth = new SimpleJdbcTemplate(npjo); + int result = jth.queryForInt(sql, args); + assertEquals(expectedResult, result); + mc.verify(); + } + + public void testQueryForIntWitSqlParameterSource() { + String sql = "SELECT COUNT(0) FROM BAR WHERE ID=:id AND XY=:xy"; + int expectedResult = 666; + int arg1 = 24; + String arg2 = "foo"; + + MockControl mc = MockControl.createControl(NamedParameterJdbcOperations.class); + NamedParameterJdbcOperations npjo = (NamedParameterJdbcOperations) mc.getMock(); + SqlParameterSource args = new MapSqlParameterSource().addValue("id", arg1).addValue("xy", arg2); + npjo.queryForInt(sql, args); + mc.setDefaultMatcher(new ArrayMatcher()); + mc.setReturnValue(expectedResult); + mc.replay(); + + SimpleJdbcTemplate jth = new SimpleJdbcTemplate(npjo); + int result = jth.queryForInt(sql, args); + assertEquals(expectedResult, result); + mc.verify(); + } + + public void testQueryForLongWithoutArgs() { + String sql = "SELECT COUNT(0) FROM BAR"; + long expectedResult = 666; + + MockControl mc = MockControl.createControl(JdbcOperations.class); + JdbcOperations jo = (JdbcOperations) mc.getMock(); + jo.queryForLong(sql); + mc.setReturnValue(expectedResult); + mc.replay(); + + SimpleJdbcTemplate jth = new SimpleJdbcTemplate(jo); + long result = jth.queryForLong(sql); + assertEquals(expectedResult, result); + + mc.verify(); + } + + public void testQueryForLongWithArgs() { + String sql = "SELECT COUNT(0) FROM BAR WHERE ID=? AND XY=?"; + long expectedResult = 666; + double arg1 = 24.7; + String arg2 = "foo"; + Object arg3 = new Object(); + + MockControl mc = MockControl.createControl(JdbcOperations.class); + JdbcOperations jo = (JdbcOperations) mc.getMock(); + jo.queryForLong(sql, new Object[]{arg1, arg2, arg3}); + mc.setDefaultMatcher(new ArrayMatcher()); + mc.setReturnValue(expectedResult); + mc.replay(); + + SimpleJdbcTemplate jth = new SimpleJdbcTemplate(jo); + long result = jth.queryForLong(sql, arg1, arg2, arg3); + assertEquals(expectedResult, result); + mc.verify(); + } + + public void testQueryForLongWithMap() { + String sql = "SELECT COUNT(0) FROM BAR WHERE ID=? AND XY=?"; + long expectedResult = 666; + double arg1 = 24.7; + String arg2 = "foo"; + Object arg3 = new Object(); + + MockControl mc = MockControl.createControl(JdbcOperations.class); + JdbcOperations jo = (JdbcOperations) mc.getMock(); + jo.queryForLong(sql, new Object[]{arg1, arg2, arg3}); + mc.setDefaultMatcher(new ArrayMatcher()); + mc.setReturnValue(expectedResult); + mc.replay(); + + SimpleJdbcTemplate jth = new SimpleJdbcTemplate(jo); + long result = jth.queryForLong(sql, arg1, arg2, arg3); + assertEquals(expectedResult, result); + mc.verify(); + } + + public void testQueryForObjectWithoutArgs() throws Exception { + String sql = "SELECT SYSDATE FROM DUAL"; + Date expectedResult = new Date(); + + MockControl mc = MockControl.createControl(JdbcOperations.class); + JdbcOperations jo = (JdbcOperations) mc.getMock(); + jo.queryForObject(sql, Date.class); + mc.setReturnValue(expectedResult); + mc.replay(); + + SimpleJdbcTemplate jth = new SimpleJdbcTemplate(jo); + Date result = jth.queryForObject(sql, Date.class); + assertEquals(expectedResult, result); + mc.verify(); + } + + public void testQueryForObjectWithArgs() throws Exception { + String sql = "SELECT SOMEDATE FROM BAR WHERE ID=? AND XY=?"; + Date expectedResult = new Date(); + double arg1 = 24.7; + String arg2 = "foo"; + Object arg3 = new Object(); + + MockControl mc = MockControl.createControl(JdbcOperations.class); + JdbcOperations jo = (JdbcOperations) mc.getMock(); + jo.queryForObject(sql, new Object[]{arg1, arg2, arg3}, Date.class); + mc.setDefaultMatcher(new ArrayMatcher()); + mc.setReturnValue(expectedResult); + mc.replay(); + + SimpleJdbcTemplate jth = new SimpleJdbcTemplate(jo); + Date result = jth.queryForObject(sql, Date.class, arg1, arg2, arg3); + assertEquals(expectedResult, result); + mc.verify(); + } + + public void testQueryForObjectWithArgArray() throws Exception { + String sql = "SELECT SOMEDATE FROM BAR WHERE ID=? AND XY=?"; + Date expectedResult = new Date(); + double arg1 = 24.7; + String arg2 = "foo"; + Object arg3 = new Object(); + + MockControl mc = MockControl.createControl(JdbcOperations.class); + JdbcOperations jo = (JdbcOperations) mc.getMock(); + jo.queryForObject(sql, new Object[]{arg1, arg2, arg3}, Date.class); + mc.setDefaultMatcher(new ArrayMatcher()); + mc.setReturnValue(expectedResult); + mc.replay(); + + SimpleJdbcTemplate jth = new SimpleJdbcTemplate(jo); + Object args = new Object[] {arg1, arg2, arg3}; + Date result = jth.queryForObject(sql, Date.class, args); + assertEquals(expectedResult, result); + mc.verify(); + } + + public void testQueryForObjectWithMap() throws Exception { + String sql = "SELECT SOMEDATE FROM BAR WHERE ID=? AND XY=?"; + Date expectedResult = new Date(); + double arg1 = 24.7; + String arg2 = "foo"; + Object arg3 = new Object(); + + MockControl mc = MockControl.createControl(JdbcOperations.class); + JdbcOperations jo = (JdbcOperations) mc.getMock(); + jo.queryForObject(sql, new Object[]{arg1, arg2, arg3}, Date.class); + mc.setDefaultMatcher(new ArrayMatcher()); + mc.setReturnValue(expectedResult); + mc.replay(); + + SimpleJdbcTemplate jth = new SimpleJdbcTemplate(jo); + Date result = jth.queryForObject(sql, Date.class, arg1, arg2, arg3); + assertEquals(expectedResult, result); + mc.verify(); + } + + public void testQueryForObjectWithRowMapperAndWithoutArgs() throws Exception { + String sql = "SELECT SYSDATE FROM DUAL"; + Date expectedResult = new Date(); + + ParameterizedRowMapper rm = new ParameterizedRowMapper() { + public Date mapRow(ResultSet rs, int rowNum) { + return new Date(); + } + }; + + MockControl mc = MockControl.createControl(JdbcOperations.class); + JdbcOperations jo = (JdbcOperations) mc.getMock(); + jo.queryForObject(sql, rm); + mc.setReturnValue(expectedResult); + mc.replay(); + + SimpleJdbcTemplate jth = new SimpleJdbcTemplate(jo); + Date result = jth.queryForObject(sql, rm); + assertEquals(expectedResult, result); + mc.verify(); + } + + public void testQueryForObjectWithRowMapperAndArgs() throws Exception { + String sql = "SELECT SOMEDATE FROM BAR WHERE ID=? AND XY=?"; + Date expectedResult = new Date(); + double arg1 = 24.7; + String arg2 = "foo"; + Object arg3 = new Object(); + + ParameterizedRowMapper rm = new ParameterizedRowMapper() { + public Date mapRow(ResultSet rs, int rowNum) { + return new Date(); + } + }; + + MockControl mc = MockControl.createControl(JdbcOperations.class); + JdbcOperations jo = (JdbcOperations) mc.getMock(); + jo.queryForObject(sql, new Object[]{arg1, arg2, arg3}, rm); + mc.setDefaultMatcher(new ArrayMatcher()); + mc.setReturnValue(expectedResult); + mc.replay(); + + SimpleJdbcTemplate jth = new SimpleJdbcTemplate(jo); + Date result = jth.queryForObject(sql, rm, arg1, arg2, arg3); + assertEquals(expectedResult, result); + mc.verify(); + } + + public void testQueryForObjectWithRowMapperAndMap() throws Exception { + String sql = "SELECT SOMEDATE FROM BAR WHERE ID=? AND XY=?"; + Date expectedResult = new Date(); + double arg1 = 24.7; + String arg2 = "foo"; + Object arg3 = new Object(); + + ParameterizedRowMapper rm = new ParameterizedRowMapper() { + public Date mapRow(ResultSet rs, int rowNum) { + return new Date(); + } + }; + + MockControl mc = MockControl.createControl(JdbcOperations.class); + JdbcOperations jo = (JdbcOperations) mc.getMock(); + jo.queryForObject(sql, new Object[]{arg1, arg2, arg3}, rm); + mc.setDefaultMatcher(new ArrayMatcher()); + mc.setReturnValue(expectedResult); + mc.replay(); + + SimpleJdbcTemplate jth = new SimpleJdbcTemplate(jo); + Date result = jth.queryForObject(sql, rm, arg1, arg2, arg3); + assertEquals(expectedResult, result); + mc.verify(); + } + + public void testQueryForListWithoutArgs() throws Exception { + testDelegation("queryForList", new Object[]{"sql"}, new Object[]{}, Collections.singletonList(new Object())); + } + + public void testQueryForListWithArgs() throws Exception { + testDelegation("queryForList", new Object[]{"sql"}, new Object[]{1, 2, 3}, new LinkedList()); + } + + public void testQueryForListWithMap() throws Exception { + HashMap args = new HashMap(3); + args.put("1", 1); + args.put("2", 2); + args.put("3", 3); + testDelegation("queryForList", new Object[]{"sql"}, new Object[]{args}, new LinkedList()); + } + + public void testQueryForListWithSqlParameterSource() throws Exception { + MapSqlParameterSource args = new MapSqlParameterSource(); + args.addValue("1", 1); + args.addValue("2", 2); + args.addValue("3", 3); + testDelegation("queryForList", new Object[]{"sql"}, new Object[]{args}, new LinkedList()); + } + + public void testQueryForMapWithoutArgs() throws Exception { + testDelegation("queryForMap", new Object[]{"sql"}, new Object[]{}, new HashMap()); + } + + public void testQueryForMapWithArgs() throws Exception { + testDelegation("queryForMap", new Object[]{"sql"}, new Object[]{1, 2, 3}, new HashMap()); + // TODO test generic type + } + + public void testQueryForMapWithMap() throws Exception { + HashMap args = new HashMap(3); + args.put("1", 1); + args.put("2", 2); + args.put("3", 3); + testDelegation("queryForMap", new Object[]{"sql"}, new Object[]{args}, new HashMap()); + } + + public void testQueryForMapWithSqlParameterSource() throws Exception { + MapSqlParameterSource args = new MapSqlParameterSource(); + args.addValue("1", 1); + args.addValue("2", 2); + args.addValue("3", 3); + testDelegation("queryForMap", new Object[]{"sql"}, new Object[]{args}, new HashMap()); + } + + public void testUpdateWithoutArgs() throws Exception { + testDelegation("update", new Object[]{"sql"}, new Object[]{}, 666); + } + + public void testUpdateWithArgs() throws Exception { + testDelegation("update", new Object[]{"sql"}, new Object[]{1, 2, 3}, 666); + } + + public void testUpdateWithMap() throws Exception { + HashMap args = new HashMap(3); + args.put("1", 1); + args.put("2", 2); + args.put("3", 3); + testDelegation("update", new Object[]{"sql"}, new Object[]{args}, 666); + } + + public void testUpdateWithSqlParameterSource() throws Exception { + MapSqlParameterSource args = new MapSqlParameterSource(); + args.addValue("1", 1); + args.addValue("2", 2); + args.addValue("3", 3); + testDelegation("update", new Object[]{"sql"}, new Object[]{args}, 666); + } + + private Object testDelegation(String methodName, Object[] typedArgs, Object[] varargs, Object expectedResult) throws Exception { + Class[] unifiedTypes; + Object[] unifiedArgs; + Class[] unifiedTypes2; + Object[] unifiedArgs2; + boolean namedParameters = false; + + if (varargs != null && varargs.length > 0) { + // Allow for Map + if (varargs[0].getClass().equals(HashMap.class)) { + unifiedTypes = new Class[typedArgs.length + 1]; + unifiedArgs = new Object[typedArgs.length + 1]; + for (int i = 0; i < typedArgs.length; i++) { + unifiedTypes[i] = typedArgs[i].getClass(); + unifiedArgs[i] = typedArgs[i]; + } + unifiedTypes[unifiedTypes.length - 1] = Map.class; + unifiedArgs[unifiedArgs.length - 1] = varargs[0]; + unifiedTypes2 = unifiedTypes; + unifiedArgs2 = unifiedArgs; + namedParameters = true; + } + else if (varargs[0].getClass().equals(MapSqlParameterSource.class)) { + unifiedTypes = new Class[typedArgs.length + 1]; + unifiedArgs = new Object[typedArgs.length + 1]; + for (int i = 0; i < typedArgs.length; i++) { + unifiedTypes[i] = typedArgs[i].getClass(); + unifiedArgs[i] = typedArgs[i]; + } + unifiedTypes[unifiedTypes.length - 1] = SqlParameterSource.class; + unifiedArgs[unifiedArgs.length - 1] = varargs[0]; + unifiedTypes2 = unifiedTypes; + unifiedArgs2 = unifiedArgs; + namedParameters = true; + } + else { + // Allow for varargs.length + unifiedTypes = new Class[typedArgs.length + 1]; + unifiedArgs = new Object[typedArgs.length + 1]; + for (int i = 0; i < unifiedTypes.length - 1; i++) { + unifiedTypes[i] = typedArgs[i].getClass(); + unifiedArgs[i] = typedArgs[i]; + } + unifiedTypes[unifiedTypes.length - 1] = Object[].class; + unifiedArgs[unifiedTypes.length - 1] = varargs; + } + + unifiedTypes2 = unifiedTypes; + unifiedArgs2 = unifiedArgs; + } + else { + unifiedTypes = new Class[typedArgs.length]; + unifiedTypes2 = new Class[typedArgs.length + 1]; + unifiedArgs = new Object[typedArgs.length]; + unifiedArgs2 = new Object[typedArgs.length + 1]; + for (int i = 0; i < typedArgs.length; i++) { + unifiedTypes[i] = unifiedTypes2[i] = typedArgs[i].getClass(); + unifiedArgs[i] = unifiedArgs2[i] = typedArgs[i]; + } + unifiedTypes2[unifiedTypes2.length - 1] = Object[].class; + unifiedArgs2[unifiedArgs2.length - 1] = new Object[]{}; + } + + MockControl mc; + JdbcOperations jo = null; + NamedParameterJdbcOperations npjo = null; + Method joMethod = null; + SimpleJdbcTemplate jth = null; + + if (namedParameters) { + mc = MockControl.createControl(NamedParameterJdbcOperations.class); + npjo = (NamedParameterJdbcOperations) mc.getMock(); + joMethod = NamedParameterJdbcOperations.class.getMethod(methodName, unifiedTypes); + joMethod.invoke(npjo, unifiedArgs); + jth = new SimpleJdbcTemplate(npjo); + } + else { + mc = MockControl.createControl(JdbcOperations.class); + jo = (JdbcOperations) mc.getMock(); + joMethod = JdbcOperations.class.getMethod(methodName, unifiedTypes); + joMethod.invoke(jo, unifiedArgs); + jth = new SimpleJdbcTemplate(jo); + } + + mc.setDefaultMatcher(new ArrayMatcher()); + + if (joMethod.getReturnType().isPrimitive()) { + // TODO bit of a hack with autoboxing passing up Integer when the return + // type is an int + mc.setReturnValue(((Integer) expectedResult).intValue()); + } + else { + mc.setReturnValue(expectedResult); + } + mc.replay(); + + Method jthMethod = SimpleJdbcTemplate.class.getMethod(methodName, unifiedTypes2); + Object result = jthMethod.invoke(jth, unifiedArgs2); + + assertEquals(expectedResult, result); + + mc.verify(); + + return result; + } + + public void testBatchUpdateWithSqlParameterSource() throws Exception { + MockControl ctrlDataSource; + DataSource mockDataSource; + MockControl ctrlConnection; + Connection mockConnection; + + ctrlConnection = MockControl.createControl(Connection.class); + mockConnection = (Connection) ctrlConnection.getMock(); + mockConnection.getMetaData(); + ctrlConnection.setDefaultReturnValue(null); + mockConnection.close(); + ctrlConnection.setDefaultVoidCallable(); + + ctrlDataSource = MockControl.createControl(DataSource.class); + mockDataSource = (DataSource) ctrlDataSource.getMock(); + mockDataSource.getConnection(); + ctrlDataSource.setDefaultReturnValue(mockConnection); + + final String sqlToUse = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; + final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id"; + final SqlParameterSource[] ids = new SqlParameterSource[2]; + ids[0] = new MapSqlParameterSource("id", 100); + ids[1] = new MapSqlParameterSource("id", 200); + final int[] rowsAffected = new int[] { 1, 2 }; + + + MockControl ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + mockPreparedStatement.getConnection(); + ctrlPreparedStatement.setReturnValue(mockConnection); + mockPreparedStatement.setObject(1, ((Integer)ids[0].getValue("id")).intValue()); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.addBatch(); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setObject(1, ((Integer)ids[1].getValue("id")).intValue()); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.addBatch(); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeBatch(); + ctrlPreparedStatement.setReturnValue(rowsAffected); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + MockControl ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MySQL"); + mockDatabaseMetaData.supportsBatchUpdates(); + ctrlDatabaseMetaData.setReturnValue(true); + + mockConnection.prepareStatement(sqlToUse); + ctrlConnection.setReturnValue(mockPreparedStatement); + mockConnection.getMetaData(); + ctrlConnection.setReturnValue(mockDatabaseMetaData, 2); + + ctrlPreparedStatement.replay(); + ctrlDatabaseMetaData.replay(); + ctrlDataSource.replay(); + ctrlConnection.replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource, false); + SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(template); + + int[] actualRowsAffected = simpleJdbcTemplate.batchUpdate(sql, ids); + + assertTrue("executed 2 updates", actualRowsAffected.length == 2); + assertEquals(rowsAffected[0], actualRowsAffected[0]); + assertEquals(rowsAffected[1], actualRowsAffected[1]); + + ctrlPreparedStatement.verify(); + ctrlDatabaseMetaData.verify(); + } + + public void testBatchUpdateWithListOfObjectArrays() throws Exception { + MockControl ctrlDataSource; + DataSource mockDataSource; + MockControl ctrlConnection; + Connection mockConnection; + + ctrlConnection = MockControl.createControl(Connection.class); + mockConnection = (Connection) ctrlConnection.getMock(); + mockConnection.getMetaData(); + ctrlConnection.setDefaultReturnValue(null); + mockConnection.close(); + ctrlConnection.setDefaultVoidCallable(); + + ctrlDataSource = MockControl.createControl(DataSource.class); + mockDataSource = (DataSource) ctrlDataSource.getMock(); + mockDataSource.getConnection(); + ctrlDataSource.setDefaultReturnValue(mockConnection); + + final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; + final List ids = new ArrayList(); + ids.add(new Object[] {100}); + ids.add(new Object[] {200}); + final int[] rowsAffected = new int[] { 1, 2 }; + + + MockControl ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + mockPreparedStatement.getConnection(); + ctrlPreparedStatement.setReturnValue(mockConnection); + mockPreparedStatement.setObject(1, ((Integer)ids.get(0)[0]).intValue()); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.addBatch(); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setObject(1, ((Integer)ids.get(1)[0]).intValue()); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.addBatch(); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeBatch(); + ctrlPreparedStatement.setReturnValue(rowsAffected); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + MockControl ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MySQL"); + mockDatabaseMetaData.supportsBatchUpdates(); + ctrlDatabaseMetaData.setReturnValue(true); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + mockConnection.getMetaData(); + ctrlConnection.setReturnValue(mockDatabaseMetaData, 2); + + ctrlPreparedStatement.replay(); + ctrlDatabaseMetaData.replay(); + ctrlDataSource.replay(); + ctrlConnection.replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource, false); + SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(template); + + int[] actualRowsAffected = simpleJdbcTemplate.batchUpdate(sql, ids); + + assertTrue("executed 2 updates", actualRowsAffected.length == 2); + assertEquals(rowsAffected[0], actualRowsAffected[0]); + assertEquals(rowsAffected[1], actualRowsAffected[1]); + + ctrlPreparedStatement.verify(); + ctrlDatabaseMetaData.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/TableMetaDataContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/TableMetaDataContextTests.java new file mode 100644 index 00000000000..a02a105c74e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/simple/TableMetaDataContextTests.java @@ -0,0 +1,241 @@ +package org.springframework.jdbc.core.simple; + +import junit.framework.TestCase; +import org.springframework.jdbc.core.metadata.TableMetaDataContext; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.SqlParameterValue; +import org.easymock.MockControl; + +import javax.sql.DataSource; +import java.util.Date; +import java.util.List; +import java.util.ArrayList; +import java.sql.Types; +import java.sql.DatabaseMetaData; +import java.sql.Connection; +import java.sql.ResultSet; + +/** + * Mock object based tests for TableMetaDataContext. + * + * @author Thomas Risberg + */ +public class TableMetaDataContextTests extends TestCase { + private MockControl ctrlDataSource; + private DataSource mockDataSource; + private MockControl ctrlConnection; + private Connection mockConnection; + private MockControl ctrlDatabaseMetaData; + private DatabaseMetaData mockDatabaseMetaData; + + private TableMetaDataContext context = new TableMetaDataContext(); + + protected void setUp() throws Exception { + super.setUp(); + + ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + + ctrlConnection = MockControl.createControl(Connection.class); + mockConnection = (Connection) ctrlConnection.getMock(); + mockConnection.getMetaData(); + ctrlConnection.setDefaultReturnValue(mockDatabaseMetaData); + mockConnection.close(); + ctrlConnection.setDefaultVoidCallable(); + + ctrlDataSource = MockControl.createControl(DataSource.class); + mockDataSource = (DataSource) ctrlDataSource.getMock(); + mockDataSource.getConnection(); + ctrlDataSource.setDefaultReturnValue(mockConnection); + + } + + protected void tearDown() throws Exception { + super.tearDown(); + ctrlDatabaseMetaData.verify(); + ctrlDataSource.verify(); + } + + protected void replay() { + ctrlDatabaseMetaData.replay(); + ctrlConnection.replay(); + ctrlDataSource.replay(); + } + + public void testMatchInParametersAndSqlTypeInfoWrapping() throws Exception { + final String TABLE = "customers"; + final String USER = "me"; + + MockControl ctrlMetaDataResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockMetaDataResultSet = (ResultSet) ctrlMetaDataResultSet.getMock(); + mockMetaDataResultSet.next(); + ctrlMetaDataResultSet.setReturnValue(true); + mockMetaDataResultSet.getString("TABLE_CAT"); + ctrlMetaDataResultSet.setReturnValue(null); + mockMetaDataResultSet.getString("TABLE_SCHEM"); + ctrlMetaDataResultSet.setReturnValue(USER); + mockMetaDataResultSet.getString("TABLE_NAME"); + ctrlMetaDataResultSet.setReturnValue(TABLE); + mockMetaDataResultSet.getString("TABLE_TYPE"); + ctrlMetaDataResultSet.setReturnValue("TABLE"); + mockMetaDataResultSet.next(); + ctrlMetaDataResultSet.setReturnValue(false); + mockMetaDataResultSet.close(); + ctrlMetaDataResultSet.setVoidCallable(); + + MockControl ctrlColumnsResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockColumnsResultSet = (ResultSet) ctrlColumnsResultSet.getMock(); + mockColumnsResultSet.next(); + ctrlColumnsResultSet.setReturnValue(true); + mockColumnsResultSet.getString("COLUMN_NAME"); + ctrlColumnsResultSet.setReturnValue("id"); + mockColumnsResultSet.getInt("DATA_TYPE"); + ctrlColumnsResultSet.setReturnValue(Types.INTEGER); + mockColumnsResultSet.getBoolean("NULLABLE"); + ctrlColumnsResultSet.setReturnValue(false); + mockColumnsResultSet.next(); + ctrlColumnsResultSet.setReturnValue(true); + mockColumnsResultSet.getString("COLUMN_NAME"); + ctrlColumnsResultSet.setReturnValue("name"); + mockColumnsResultSet.getInt("DATA_TYPE"); + ctrlColumnsResultSet.setReturnValue(Types.VARCHAR); + mockColumnsResultSet.getBoolean("NULLABLE"); + ctrlColumnsResultSet.setReturnValue(true); + mockColumnsResultSet.next(); + ctrlColumnsResultSet.setReturnValue(true); + mockColumnsResultSet.getString("COLUMN_NAME"); + ctrlColumnsResultSet.setReturnValue("customersince"); + mockColumnsResultSet.getInt("DATA_TYPE"); + ctrlColumnsResultSet.setReturnValue(Types.DATE); + mockColumnsResultSet.getBoolean("NULLABLE"); + ctrlColumnsResultSet.setReturnValue(true); + mockColumnsResultSet.next(); + ctrlColumnsResultSet.setReturnValue(true); + mockColumnsResultSet.getString("COLUMN_NAME"); + ctrlColumnsResultSet.setReturnValue("version"); + mockColumnsResultSet.getInt("DATA_TYPE"); + ctrlColumnsResultSet.setReturnValue(Types.NUMERIC); + mockColumnsResultSet.getBoolean("NULLABLE"); + ctrlColumnsResultSet.setReturnValue(false); + mockColumnsResultSet.next(); + ctrlColumnsResultSet.setReturnValue(false); + mockColumnsResultSet.close(); + ctrlColumnsResultSet.setVoidCallable(); + + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MyDB"); + mockDatabaseMetaData.supportsGetGeneratedKeys(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MyDB"); + mockDatabaseMetaData.getDatabaseProductVersion(); + ctrlDatabaseMetaData.setReturnValue("1.0"); + mockDatabaseMetaData.getUserName(); + ctrlDatabaseMetaData.setReturnValue(USER); + mockDatabaseMetaData.storesUpperCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.storesLowerCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(true); + mockDatabaseMetaData.getTables(null, null, TABLE, null); + ctrlDatabaseMetaData.setReturnValue(mockMetaDataResultSet); + mockDatabaseMetaData.getColumns(null, USER, TABLE, null); + ctrlDatabaseMetaData.setReturnValue(mockColumnsResultSet); + + ctrlMetaDataResultSet.replay(); + ctrlColumnsResultSet.replay(); + replay(); + + MapSqlParameterSource map = new MapSqlParameterSource(); + map.addValue("id", 1); + map.addValue("name", "Sven"); + map.addValue("customersince", new Date()); + map.addValue("version", 0); + map.registerSqlType("customersince", Types.DATE); + map.registerSqlType("version", Types.NUMERIC); + + context.setTableName(TABLE); + context.processMetaData(mockDataSource, new ArrayList(), new String[] {}); + + List values = context.matchInParameterValuesWithInsertColumns(map); + + assertEquals("wrong number of parameters: ", 4, values.size()); + assertTrue("id not wrapped with type info", values.get(0) instanceof Number); + assertTrue("name not wrapped with type info", values.get(1) instanceof String); + assertTrue("date wrapped with type info", values.get(2) instanceof SqlParameterValue); + assertTrue("version wrapped with type info", values.get(3) instanceof SqlParameterValue); + } + + public void testTableWithSingleColumnGeneratedKey() throws Exception { + final String TABLE = "customers"; + final String USER = "me"; + + MockControl ctrlMetaDataResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockMetaDataResultSet = (ResultSet) ctrlMetaDataResultSet.getMock(); + mockMetaDataResultSet.next(); + ctrlMetaDataResultSet.setReturnValue(true); + mockMetaDataResultSet.getString("TABLE_CAT"); + ctrlMetaDataResultSet.setReturnValue(null); + mockMetaDataResultSet.getString("TABLE_SCHEM"); + ctrlMetaDataResultSet.setReturnValue(USER); + mockMetaDataResultSet.getString("TABLE_NAME"); + ctrlMetaDataResultSet.setReturnValue(TABLE); + mockMetaDataResultSet.getString("TABLE_TYPE"); + ctrlMetaDataResultSet.setReturnValue("TABLE"); + mockMetaDataResultSet.next(); + ctrlMetaDataResultSet.setReturnValue(false); + mockMetaDataResultSet.close(); + ctrlMetaDataResultSet.setVoidCallable(); + + MockControl ctrlColumnsResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockColumnsResultSet = (ResultSet) ctrlColumnsResultSet.getMock(); + mockColumnsResultSet.next(); + ctrlColumnsResultSet.setReturnValue(true); + mockColumnsResultSet.getString("COLUMN_NAME"); + ctrlColumnsResultSet.setReturnValue("id"); + mockColumnsResultSet.getInt("DATA_TYPE"); + ctrlColumnsResultSet.setReturnValue(Types.INTEGER); + mockColumnsResultSet.getBoolean("NULLABLE"); + ctrlColumnsResultSet.setReturnValue(false); + mockColumnsResultSet.next(); + ctrlColumnsResultSet.setReturnValue(false); + mockColumnsResultSet.close(); + ctrlColumnsResultSet.setVoidCallable(); + + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MyDB"); + mockDatabaseMetaData.supportsGetGeneratedKeys(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MyDB"); + mockDatabaseMetaData.getDatabaseProductVersion(); + ctrlDatabaseMetaData.setReturnValue("1.0"); + mockDatabaseMetaData.getUserName(); + ctrlDatabaseMetaData.setReturnValue(USER); + mockDatabaseMetaData.storesUpperCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(false); + mockDatabaseMetaData.storesLowerCaseIdentifiers(); + ctrlDatabaseMetaData.setReturnValue(true); + mockDatabaseMetaData.getTables(null, null, TABLE, null); + ctrlDatabaseMetaData.setReturnValue(mockMetaDataResultSet); + mockDatabaseMetaData.getColumns(null, USER, TABLE, null); + ctrlDatabaseMetaData.setReturnValue(mockColumnsResultSet); + + ctrlMetaDataResultSet.replay(); + ctrlColumnsResultSet.replay(); + replay(); + + MapSqlParameterSource map = new MapSqlParameterSource(); + + String[] keyCols = new String[] {"id"}; + + context.setTableName(TABLE); + context.processMetaData(mockDataSource, new ArrayList(), keyCols); + + List values = context.matchInParameterValuesWithInsertColumns(map); + + String insertString = context.createInsertString(keyCols); + + assertEquals("wrong number of parameters: ", 0, values.size()); + assertEquals("empty insert not generated correctly", "INSERT INTO customers () VALUES()", insertString); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/AnnotationLazyInitMBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/AnnotationLazyInitMBeanTests.java new file mode 100644 index 00000000000..f75bd7d50f4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/AnnotationLazyInitMBeanTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.annotation; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import junit.framework.TestCase; + +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.jmx.support.ObjectNameManager; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class AnnotationLazyInitMBeanTests extends TestCase { + + public void testLazyNaming() throws Exception { + ConfigurableApplicationContext ctx = + new ClassPathXmlApplicationContext("org/springframework/jmx/export/annotation/lazyNaming.xml"); + try { + MBeanServer server = (MBeanServer) ctx.getBean("server"); + ObjectName oname = ObjectNameManager.getInstance("bean:name=testBean4"); + assertNotNull(server.getObjectInstance(oname)); + String name = (String) server.getAttribute(oname, "Name"); + assertEquals("Invalid name returned", "TEST", name); + } + finally { + ctx.close(); + } + } + + public void testLazyAssembling() throws Exception { + ConfigurableApplicationContext ctx = + new ClassPathXmlApplicationContext("org/springframework/jmx/export/annotation/lazyAssembling.xml"); + try { + MBeanServer server = (MBeanServer) ctx.getBean("server"); + + ObjectName oname = ObjectNameManager.getInstance("bean:name=testBean4"); + assertNotNull(server.getObjectInstance(oname)); + String name = (String) server.getAttribute(oname, "Name"); + assertEquals("Invalid name returned", "TEST", name); + + oname = ObjectNameManager.getInstance("spring:mbean=true"); + assertNotNull(server.getObjectInstance(oname)); + name = (String) server.getAttribute(oname, "Name"); + assertEquals("Invalid name returned", "Rob Harrop", name); + + oname = ObjectNameManager.getInstance("spring:mbean=another"); + assertNotNull(server.getObjectInstance(oname)); + name = (String) server.getAttribute(oname, "Name"); + assertEquals("Invalid name returned", "Juergen Hoeller", name); + } + finally { + ctx.close(); + } + } + + public void testComponentScan() throws Exception { + ConfigurableApplicationContext ctx = + new ClassPathXmlApplicationContext("org/springframework/jmx/export/annotation/componentScan.xml"); + try { + MBeanServer server = (MBeanServer) ctx.getBean("server"); + ObjectName oname = ObjectNameManager.getInstance("bean:name=testBean4"); + assertNotNull(server.getObjectInstance(oname)); + String name = (String) server.getAttribute(oname, "Name"); + assertNull(name); + } + finally { + ctx.close(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/AnnotationMetadataAssemblerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/AnnotationMetadataAssemblerTests.java new file mode 100644 index 00000000000..be94642571b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/AnnotationMetadataAssemblerTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2005 the original author 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.jmx.export.annotation; + +import org.springframework.jmx.IJmxTestBean; +import org.springframework.jmx.export.assembler.AbstractMetadataAssemblerTests; +import org.springframework.jmx.export.metadata.JmxAttributeSource; + +/** + * @author Rob Harrop + */ +public class AnnotationMetadataAssemblerTests extends AbstractMetadataAssemblerTests { + + private static final String OBJECT_NAME = "bean:name=testBean4"; + + protected JmxAttributeSource getAttributeSource() { + return new AnnotationJmxAttributeSource(); + } + + protected String getObjectName() { + return OBJECT_NAME; + } + + protected IJmxTestBean createJmxTestBean() { + return new AnnotationTestBean(); + } + + protected String getApplicationContextPath() { + return "org/springframework/jmx/export/annotation/annotations.xml"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBean.java new file mode 100644 index 00000000000..7837975015d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBean.java @@ -0,0 +1,101 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.annotation; + +import org.springframework.jmx.IJmxTestBean; +import org.springframework.stereotype.Service; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +@Service("testBean") +@ManagedResource(objectName = "bean:name=testBean4", description = "My Managed Bean", log = true, + logFile = "jmx.log", currencyTimeLimit = 15, persistPolicy = "OnUpdate", persistPeriod = 200, + persistLocation = "./foo", persistName = "bar.jmx") +@ManagedNotifications({@ManagedNotification(name="My Notification", notificationTypes={"type.foo", "type.bar"})}) +public class AnnotationTestBean implements IJmxTestBean { + + private String name; + + private String nickName; + + private int age; + + private boolean isSuperman; + + + @ManagedAttribute(description = "The Age Attribute", currencyTimeLimit = 15) + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + @ManagedOperation(currencyTimeLimit = 30) + public long myOperation() { + return 1L; + } + + @ManagedAttribute(description = "The Name Attribute", + currencyTimeLimit = 20, + defaultValue = "bar", + persistPolicy = "OnUpdate") + public void setName(String name) { + this.name = name; + } + + @ManagedAttribute(defaultValue = "foo", persistPeriod = 300) + public String getName() { + return name; + } + + @ManagedAttribute(description = "The Nick Name Attribute") + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getNickName() { + return this.nickName; + } + + public void setSuperman(boolean superman) { + this.isSuperman = superman; + } + + @ManagedAttribute(description = "The Is Superman Attribute") + public boolean isSuperman() { + return isSuperman; + } + + @org.springframework.jmx.export.annotation.ManagedOperation(description = "Add Two Numbers Together") + @ManagedOperationParameters({@ManagedOperationParameter(name="x", description="Left operand"), + @ManagedOperationParameter(name="y", description="Right operand")}) + public int add(int x, int y) { + return x + y; + } + + /** + * Test method that is not exposed by the MetadataAssembler. + */ + public void dontExposeMe() { + throw new RuntimeException(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/JmxUtilsAnnotationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/JmxUtilsAnnotationTests.java new file mode 100644 index 00000000000..d409d1e8e2c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/JmxUtilsAnnotationTests.java @@ -0,0 +1,77 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.annotation; + +import javax.management.MXBean; + +import junit.framework.TestCase; + +import org.springframework.core.JdkVersion; +import org.springframework.jmx.support.JmxUtils; + +/** + * @author Juergen Hoeller + */ +public class JmxUtilsAnnotationTests extends TestCase { + + public void testNotMXBean() throws Exception { + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_16) { + return; + } + FooNotX foo = new FooNotX(); + assertFalse("MXBean annotation not detected correctly", JmxUtils.isMBean(foo.getClass())); + } + + public void testAnnotatedMXBean() throws Exception { + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_16) { + return; + } + FooX foo = new FooX(); + assertTrue("MXBean annotation not detected correctly", JmxUtils.isMBean(foo.getClass())); + } + + + @MXBean(false) + public static interface FooNotMXBean { + + String getName(); + } + + + public static class FooNotX implements FooNotMXBean { + + public String getName() { + return "Rob Harrop"; + } + } + + + @MXBean(true) + public static interface FooIfc { + + String getName(); + } + + + public static class FooX implements FooIfc { + + public String getName() { + return "Rob Harrop"; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/annotations.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/annotations.xml new file mode 100644 index 00000000000..7e044ed9d0e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/annotations.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + TEST + + + 100 + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/componentScan.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/componentScan.xml new file mode 100644 index 00000000000..91cb4bdae2b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/componentScan.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/lazyAssembling.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/lazyAssembling.xml new file mode 100644 index 00000000000..b11a795aac3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/lazyAssembling.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/lazyNaming.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/lazyNaming.xml new file mode 100644 index 00000000000..92e07746efe --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/annotation/lazyNaming.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/ibatis/SqlMapClientTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/ibatis/SqlMapClientTests.java new file mode 100644 index 00000000000..19f24775072 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/ibatis/SqlMapClientTests.java @@ -0,0 +1,462 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.ibatis; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import com.ibatis.common.util.PaginatedArrayList; +import com.ibatis.common.util.PaginatedList; +import com.ibatis.sqlmap.client.SqlMapClient; +import com.ibatis.sqlmap.client.SqlMapExecutor; +import com.ibatis.sqlmap.client.SqlMapSession; +import com.ibatis.sqlmap.client.event.RowHandler; +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.JdbcUpdateAffectedIncorrectNumberOfRowsException; +import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport; + +/** + * @author Juergen Hoeller + * @author Alef Arendsen + * @since 09.10.2004 + */ +public class SqlMapClientTests extends TestCase { + + public void testSqlMapClientFactoryBeanWithoutConfig() throws Exception { + SqlMapClientFactoryBean factory = new SqlMapClientFactoryBean(); + // explicitly set to null, don't know why ;-) + factory.setConfigLocation(null); + try { + factory.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + public void testSqlMapClientTemplate() throws SQLException { + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.close(); + conControl.setVoidCallable(1); + dsControl.replay(); + conControl.replay(); + + MockControl sessionControl = MockControl.createControl(SqlMapSession.class); + final SqlMapSession session = (SqlMapSession) sessionControl.getMock(); + MockControl clientControl = MockControl.createControl(SqlMapClient.class); + SqlMapClient client = (SqlMapClient) clientControl.getMock(); + client.openSession(); + clientControl.setReturnValue(session, 1); + session.getCurrentConnection(); + sessionControl.setReturnValue(null, 1); + session.setUserConnection(con); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setVoidCallable(1); + sessionControl.replay(); + clientControl.replay(); + + SqlMapClientTemplate template = new SqlMapClientTemplate(); + template.setDataSource(ds); + template.setSqlMapClient(client); + template.afterPropertiesSet(); + Object result = template.execute(new SqlMapClientCallback() { + public Object doInSqlMapClient(SqlMapExecutor executor) { + assertTrue(executor == session); + return "done"; + } + }); + assertEquals("done", result); + dsControl.verify(); + conControl.verify(); + sessionControl.verify(); + clientControl.verify(); + } + + public void testSqlMapClientTemplateWithNestedSqlMapSession() throws SQLException { + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + dsControl.replay(); + conControl.replay(); + + MockControl sessionControl = MockControl.createControl(SqlMapSession.class); + final SqlMapSession session = (SqlMapSession) sessionControl.getMock(); + MockControl clientControl = MockControl.createControl(SqlMapClient.class); + SqlMapClient client = (SqlMapClient) clientControl.getMock(); + client.openSession(); + clientControl.setReturnValue(session, 1); + session.getCurrentConnection(); + sessionControl.setReturnValue(con, 1); + sessionControl.replay(); + clientControl.replay(); + + SqlMapClientTemplate template = new SqlMapClientTemplate(); + template.setDataSource(ds); + template.setSqlMapClient(client); + template.afterPropertiesSet(); + Object result = template.execute(new SqlMapClientCallback() { + public Object doInSqlMapClient(SqlMapExecutor executor) { + assertTrue(executor == session); + return "done"; + } + }); + assertEquals("done", result); + dsControl.verify(); + conControl.verify(); + sessionControl.verify(); + clientControl.verify(); + } + + public void testQueryForObjectOnSqlMapSession() throws SQLException { + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl clientControl = MockControl.createControl(SqlMapClient.class); + SqlMapClient client = (SqlMapClient) clientControl.getMock(); + MockControl sessionControl = MockControl.createControl(SqlMapSession.class); + SqlMapSession session = (SqlMapSession) sessionControl.getMock(); + + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.close(); + conControl.setVoidCallable(1); + client.getDataSource(); + clientControl.setReturnValue(ds, 2); + client.openSession(); + clientControl.setReturnValue(session, 1); + session.getCurrentConnection(); + sessionControl.setReturnValue(null, 1); + session.setUserConnection(con); + sessionControl.setVoidCallable(1); + session.queryForObject("myStatement", "myParameter"); + sessionControl.setReturnValue("myResult", 1); + session.close(); + sessionControl.setVoidCallable(1); + + dsControl.replay(); + conControl.replay(); + clientControl.replay(); + sessionControl.replay(); + + SqlMapClientTemplate template = new SqlMapClientTemplate(); + template.setSqlMapClient(client); + template.afterPropertiesSet(); + assertEquals("myResult", template.queryForObject("myStatement", "myParameter")); + + dsControl.verify(); + clientControl.verify(); + } + + public void testQueryForObject() throws SQLException { + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.queryForObject("myStatement", null); + template.executorControl.setReturnValue("myResult", 1); + template.executorControl.replay(); + assertEquals("myResult", template.queryForObject("myStatement")); + template.executorControl.verify(); + } + + public void testQueryForObjectWithParameter() throws SQLException { + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.queryForObject("myStatement", "myParameter"); + template.executorControl.setReturnValue("myResult", 1); + template.executorControl.replay(); + assertEquals("myResult", template.queryForObject("myStatement", "myParameter")); + template.executorControl.verify(); + } + + public void testQueryForObjectWithParameterAndResultObject() throws SQLException { + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.queryForObject("myStatement", "myParameter", "myResult"); + template.executorControl.setReturnValue("myResult", 1); + template.executorControl.replay(); + assertEquals("myResult", template.queryForObject("myStatement", "myParameter", "myResult")); + template.executorControl.verify(); + } + + public void testQueryForList() throws SQLException { + List result = new ArrayList(); + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.queryForList("myStatement", null); + template.executorControl.setReturnValue(result, 1); + template.executorControl.replay(); + assertEquals(result, template.queryForList("myStatement")); + template.executorControl.verify(); + } + + public void testQueryForListWithParameter() throws SQLException { + List result = new ArrayList(); + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.queryForList("myStatement", "myParameter"); + template.executorControl.setReturnValue(result, 1); + template.executorControl.replay(); + assertEquals(result, template.queryForList("myStatement", "myParameter")); + template.executorControl.verify(); + } + + public void testQueryForListWithResultSize() throws SQLException { + List result = new ArrayList(); + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.queryForList("myStatement", null, 10, 20); + template.executorControl.setReturnValue(result, 1); + template.executorControl.replay(); + assertEquals(result, template.queryForList("myStatement", 10, 20)); + template.executorControl.verify(); + } + + public void testQueryForListParameterAndWithResultSize() throws SQLException { + List result = new ArrayList(); + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.queryForList("myStatement", "myParameter", 10, 20); + template.executorControl.setReturnValue(result, 1); + template.executorControl.replay(); + assertEquals(result, template.queryForList("myStatement", "myParameter", 10, 20)); + template.executorControl.verify(); + } + + public void testQueryWithRowHandler() throws SQLException { + RowHandler rowHandler = new TestRowHandler(); + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.queryWithRowHandler("myStatement", null, rowHandler); + template.executorControl.setVoidCallable(1); + template.executorControl.replay(); + template.queryWithRowHandler("myStatement", rowHandler); + template.executorControl.verify(); + } + + public void testQueryWithRowHandlerWithParameter() throws SQLException { + RowHandler rowHandler = new TestRowHandler(); + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.queryWithRowHandler("myStatement", "myParameter", rowHandler); + template.executorControl.setVoidCallable(1); + template.executorControl.replay(); + template.queryWithRowHandler("myStatement", "myParameter", rowHandler); + template.executorControl.verify(); + } + + public void testQueryForPaginatedList() throws SQLException { + PaginatedList result = new PaginatedArrayList(10); + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.queryForPaginatedList("myStatement", null, 10); + template.executorControl.setReturnValue(result, 1); + template.executorControl.replay(); + assertEquals(result, template.queryForPaginatedList("myStatement", 10)); + template.executorControl.verify(); + } + + public void testQueryForPaginatedListWithParameter() throws SQLException { + PaginatedList result = new PaginatedArrayList(10); + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.queryForPaginatedList("myStatement", "myParameter", 10); + template.executorControl.setReturnValue(result, 1); + template.executorControl.replay(); + assertEquals(result, template.queryForPaginatedList("myStatement", "myParameter", 10)); + template.executorControl.verify(); + } + + public void testQueryForMap() throws SQLException { + Map result = new HashMap(); + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.queryForMap("myStatement", "myParameter", "myKey"); + template.executorControl.setReturnValue(result, 1); + template.executorControl.replay(); + assertEquals(result, template.queryForMap("myStatement", "myParameter", "myKey")); + template.executorControl.verify(); + } + + public void testQueryForMapWithValueProperty() throws SQLException { + Map result = new HashMap(); + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.queryForMap("myStatement", "myParameter", "myKey", "myValue"); + template.executorControl.setReturnValue(result, 1); + template.executorControl.replay(); + assertEquals(result, template.queryForMap("myStatement", "myParameter", "myKey", "myValue")); + template.executorControl.verify(); + } + + public void testInsert() throws SQLException { + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.insert("myStatement", null); + template.executorControl.setReturnValue("myResult", 1); + template.executorControl.replay(); + assertEquals("myResult", template.insert("myStatement")); + template.executorControl.verify(); + } + + public void testInsertWithParameter() throws SQLException { + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.insert("myStatement", "myParameter"); + template.executorControl.setReturnValue("myResult", 1); + template.executorControl.replay(); + assertEquals("myResult", template.insert("myStatement", "myParameter")); + template.executorControl.verify(); + } + + public void testUpdate() throws SQLException { + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.update("myStatement", null); + template.executorControl.setReturnValue(10, 1); + template.executorControl.replay(); + assertEquals(10, template.update("myStatement")); + template.executorControl.verify(); + } + + public void testUpdateWithParameter() throws SQLException { + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.update("myStatement", "myParameter"); + template.executorControl.setReturnValue(10, 1); + template.executorControl.replay(); + assertEquals(10, template.update("myStatement", "myParameter")); + template.executorControl.verify(); + } + + public void testUpdateWithRequiredRowsAffected() throws SQLException { + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.update("myStatement", "myParameter"); + template.executorControl.setReturnValue(10, 1); + template.executorControl.replay(); + template.update("myStatement", "myParameter", 10); + template.executorControl.verify(); + } + + public void testUpdateWithRequiredRowsAffectedAndInvalidRowCount() throws SQLException { + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.update("myStatement", "myParameter"); + template.executorControl.setReturnValue(20, 1); + template.executorControl.replay(); + try { + template.update("myStatement", "myParameter", 10); + fail("Should have thrown JdbcUpdateAffectedIncorrectNumberOfRowsException"); + } + catch (JdbcUpdateAffectedIncorrectNumberOfRowsException ex) { + // expected + assertEquals(10, ex.getExpectedRowsAffected()); + assertEquals(20, ex.getActualRowsAffected()); + } + template.executorControl.verify(); + } + + public void testDelete() throws SQLException { + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.delete("myStatement", null); + template.executorControl.setReturnValue(10, 1); + template.executorControl.replay(); + assertEquals(10, template.delete("myStatement")); + template.executorControl.verify(); + } + + public void testDeleteWithParameter() throws SQLException { + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.delete("myStatement", "myParameter"); + template.executorControl.setReturnValue(10, 1); + template.executorControl.replay(); + assertEquals(10, template.delete("myStatement", "myParameter")); + template.executorControl.verify(); + } + + public void testDeleteWithRequiredRowsAffected() throws SQLException { + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.delete("myStatement", "myParameter"); + template.executorControl.setReturnValue(10, 1); + template.executorControl.replay(); + template.delete("myStatement", "myParameter", 10); + template.executorControl.verify(); + } + + public void testDeleteWithRequiredRowsAffectedAndInvalidRowCount() throws SQLException { + TestSqlMapClientTemplate template = new TestSqlMapClientTemplate(); + template.executor.delete("myStatement", "myParameter"); + template.executorControl.setReturnValue(20, 1); + template.executorControl.replay(); + try { + template.delete("myStatement", "myParameter", 10); + fail("Should have thrown JdbcUpdateAffectedIncorrectNumberOfRowsException"); + } + catch (JdbcUpdateAffectedIncorrectNumberOfRowsException ex) { + // expected + assertEquals(10, ex.getExpectedRowsAffected()); + assertEquals(20, ex.getActualRowsAffected()); + } + template.executorControl.verify(); + } + + public void testSqlMapClientDaoSupport() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + SqlMapClientDaoSupport testDao = new SqlMapClientDaoSupport() { + }; + testDao.setDataSource(ds); + assertEquals(ds, testDao.getDataSource()); + + MockControl clientControl = MockControl.createControl(SqlMapClient.class); + SqlMapClient client = (SqlMapClient) clientControl.getMock(); + clientControl.replay(); + + testDao.setSqlMapClient(client); + assertEquals(client, testDao.getSqlMapClient()); + + SqlMapClientTemplate template = new SqlMapClientTemplate(); + template.setDataSource(ds); + template.setSqlMapClient(client); + testDao.setSqlMapClientTemplate(template); + assertEquals(template, testDao.getSqlMapClientTemplate()); + + testDao.afterPropertiesSet(); + } + + + private static class TestSqlMapClientTemplate extends SqlMapClientTemplate { + + public MockControl executorControl = MockControl.createControl(SqlMapExecutor.class); + public SqlMapExecutor executor = (SqlMapExecutor) executorControl.getMock(); + + public Object execute(SqlMapClientCallback action) throws DataAccessException { + try { + return action.doInSqlMapClient(executor); + } + catch (SQLException ex) { + throw getExceptionTranslator().translate("SqlMapClient operation", null, ex); + } + } + } + + + private static class TestRowHandler implements RowHandler { + + public void handleRow(Object row) { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/ibatis/support/LobTypeHandlerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/ibatis/support/LobTypeHandlerTests.java new file mode 100644 index 00000000000..6732ddcd548 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/ibatis/support/LobTypeHandlerTests.java @@ -0,0 +1,241 @@ +/* + * Copyright 2002-2005 the original author 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.orm.ibatis.support; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; + +import javax.sql.DataSource; + +import junit.framework.TestCase; +import org.easymock.ArgumentsMatcher; +import org.easymock.MockControl; + +import org.springframework.jdbc.datasource.DataSourceUtils; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy; +import org.springframework.jdbc.support.lob.LobCreator; +import org.springframework.jdbc.support.lob.LobHandler; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Juergen Hoeller + * @since 27.02.2005 + */ +public class LobTypeHandlerTests extends TestCase { + + private MockControl rsControl = MockControl.createControl(ResultSet.class); + private ResultSet rs = (ResultSet) rsControl.getMock(); + private MockControl psControl = MockControl.createControl(PreparedStatement.class); + private PreparedStatement ps = (PreparedStatement) psControl.getMock(); + + private MockControl lobHandlerControl = MockControl.createControl(LobHandler.class); + private LobHandler lobHandler = (LobHandler) lobHandlerControl.getMock(); + private MockControl lobCreatorControl = MockControl.createControl(LobCreator.class); + private LobCreator lobCreator = (LobCreator) lobCreatorControl.getMock(); + + protected void setUp() throws SQLException { + rs.findColumn("column"); + rsControl.setReturnValue(1); + + lobHandler.getLobCreator(); + lobHandlerControl.setReturnValue(lobCreator); + lobCreator.close(); + lobCreatorControl.setVoidCallable(1); + + rsControl.replay(); + psControl.replay(); + } + + public void testClobStringTypeHandler() throws Exception { + lobHandler.getClobAsString(rs, 1); + lobHandlerControl.setReturnValue("content", 2); + lobCreator.setClobAsString(ps, 1, "content"); + lobCreatorControl.setVoidCallable(1); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + ClobStringTypeHandler type = new ClobStringTypeHandler(lobHandler); + assertEquals("content", type.valueOf("content")); + assertEquals("content", type.getResult(rs, "column")); + assertEquals("content", type.getResult(rs, 1)); + + TransactionSynchronizationManager.initSynchronization(); + try { + type.setParameter(ps, 1, "content", null); + List synchs = TransactionSynchronizationManager.getSynchronizations(); + assertEquals(1, synchs.size()); + assertTrue(synchs.get(0).getClass().getName().endsWith("LobCreatorSynchronization")); + ((TransactionSynchronization) synchs.get(0)).beforeCompletion(); + ((TransactionSynchronization) synchs.get(0)).afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + } + } + + public void testClobStringTypeWithSynchronizedConnection() throws Exception { + DataSource dsTarget = new DriverManagerDataSource(); + DataSource ds = new LazyConnectionDataSourceProxy(dsTarget); + + lobHandler.getClobAsString(rs, 1); + lobHandlerControl.setReturnValue("content", 2); + lobCreator.setClobAsString(ps, 1, "content"); + lobCreatorControl.setVoidCallable(1); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + ClobStringTypeHandler type = new ClobStringTypeHandler(lobHandler); + assertEquals("content", type.valueOf("content")); + assertEquals("content", type.getResult(rs, "column")); + assertEquals("content", type.getResult(rs, 1)); + + TransactionSynchronizationManager.initSynchronization(); + try { + DataSourceUtils.getConnection(ds); + type.setParameter(ps, 1, "content", null); + List synchs = TransactionSynchronizationManager.getSynchronizations(); + assertEquals(2, synchs.size()); + assertTrue(synchs.get(0).getClass().getName().endsWith("LobCreatorSynchronization")); + ((TransactionSynchronization) synchs.get(0)).beforeCompletion(); + ((TransactionSynchronization) synchs.get(0)).afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + ((TransactionSynchronization) synchs.get(1)).beforeCompletion(); + ((TransactionSynchronization) synchs.get(1)).afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + } + } + + public void testBlobByteArrayType() throws Exception { + byte[] content = "content".getBytes(); + lobHandler.getBlobAsBytes(rs, 1); + lobHandlerControl.setReturnValue(content, 2); + lobCreator.setBlobAsBytes(ps, 1, content); + lobCreatorControl.setVoidCallable(1); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + BlobByteArrayTypeHandler type = new BlobByteArrayTypeHandler(lobHandler); + assertTrue(Arrays.equals(content, (byte[]) type.valueOf("content"))); + assertEquals(content, type.getResult(rs, "column")); + assertEquals(content, type.getResult(rs, 1)); + + TransactionSynchronizationManager.initSynchronization(); + try { + type.setParameter(ps, 1, content, null); + List synchs = TransactionSynchronizationManager.getSynchronizations(); + assertEquals(1, synchs.size()); + ((TransactionSynchronization) synchs.get(0)).beforeCompletion(); + ((TransactionSynchronization) synchs.get(0)).afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + } + } + + public void testBlobSerializableType() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject("content"); + oos.close(); + + lobHandler.getBlobAsBinaryStream(rs, 1); + lobHandlerControl.setReturnValue(new ByteArrayInputStream(baos.toByteArray()), 1); + lobHandler.getBlobAsBinaryStream(rs, 1); + lobHandlerControl.setReturnValue(new ByteArrayInputStream(baos.toByteArray()), 1); + lobCreator.setBlobAsBytes(ps, 1, baos.toByteArray()); + lobCreatorControl.setMatcher(new ArgumentsMatcher() { + public boolean matches(Object[] o1, Object[] o2) { + return Arrays.equals((byte[]) o1[2], (byte[]) o2[2]); + } + public String toString(Object[] objects) { + return null; + } + }); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + BlobSerializableTypeHandler type = new BlobSerializableTypeHandler(lobHandler); + assertEquals("content", type.valueOf("content")); + assertEquals("content", type.getResult(rs, "column")); + assertEquals("content", type.getResult(rs, 1)); + + TransactionSynchronizationManager.initSynchronization(); + try { + type.setParameter(ps, 1, "content", null); + List synchs = TransactionSynchronizationManager.getSynchronizations(); + assertEquals(1, synchs.size()); + ((TransactionSynchronization) synchs.get(0)).beforeCompletion(); + ((TransactionSynchronization) synchs.get(0)).afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + } + } + + public void testBlobSerializableTypeWithNull() throws Exception { + lobHandler.getBlobAsBinaryStream(rs, 1); + lobHandlerControl.setReturnValue(null, 2); + lobCreator.setBlobAsBytes(ps, 1, null); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + BlobSerializableTypeHandler type = new BlobSerializableTypeHandler(lobHandler); + assertEquals(null, type.valueOf(null)); + assertEquals(null, type.getResult(rs, "column")); + assertEquals(null, type.getResult(rs, 1)); + + TransactionSynchronizationManager.initSynchronization(); + try { + type.setParameter(ps, 1, null, null); + List synchs = TransactionSynchronizationManager.getSynchronizations(); + assertEquals(1, synchs.size()); + ((TransactionSynchronization) synchs.get(0)).beforeCompletion(); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + } + } + + protected void tearDown() { + try { + rsControl.verify(); + psControl.verify(); + lobHandlerControl.verify(); + lobCreatorControl.verify(); + } + catch (IllegalStateException ex) { + // ignore: test method didn't call replay + } + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/AbstractContainerEntityManagerFactoryIntegrationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/AbstractContainerEntityManagerFactoryIntegrationTests.java new file mode 100644 index 00000000000..1afc40bc2cf --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/AbstractContainerEntityManagerFactoryIntegrationTests.java @@ -0,0 +1,258 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa; + +import java.lang.reflect.Proxy; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.EntityNotFoundException; +import javax.persistence.FlushModeType; +import javax.persistence.NoResultException; +import javax.persistence.Query; + +import org.springframework.orm.jpa.domain.DriversLicense; +import org.springframework.orm.jpa.domain.Person; +import org.springframework.test.annotation.ExpectedException; +import org.springframework.test.annotation.NotTransactional; +import org.springframework.test.annotation.Repeat; +import org.springframework.test.annotation.Timed; + +/** + * Integration tests for LocalContainerEntityManagerFactoryBean. + * Uses an in-memory database. + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +public abstract class AbstractContainerEntityManagerFactoryIntegrationTests + extends AbstractEntityManagerFactoryIntegrationTests { + + @NotTransactional + public void testEntityManagerFactoryImplementsEntityManagerFactoryInfo() { + assertTrue(Proxy.isProxyClass(entityManagerFactory.getClass())); + assertTrue("Must have introduced config interface", + entityManagerFactory instanceof EntityManagerFactoryInfo); + EntityManagerFactoryInfo emfi = (EntityManagerFactoryInfo) entityManagerFactory; + //assertEquals("Person", emfi.getPersistenceUnitName()); + assertNotNull("PersistenceUnitInfo must be available", emfi.getPersistenceUnitInfo()); + assertNotNull("Raw EntityManagerFactory must be available", emfi.getNativeEntityManagerFactory()); + } + + public void testStateClean() { + assertEquals("Should be no people from previous transactions", + 0, countRowsInTable("person")); + } + + @Repeat(5) + public void testJdbcTx1() throws Exception { + testJdbcTx2(); + } + + @Timed(millis=273) + public void testJdbcTx2() throws InterruptedException { + //Thread.sleep(2000); + assertEquals("Any previous tx must have been rolled back", 0, countRowsInTable("person")); + //insertPerson("foo"); + executeSqlScript("/sql/insertPerson.sql", false); + } + + //@NotTransactional + public void testEntityManagerProxyIsProxy() { + assertTrue(Proxy.isProxyClass(sharedEntityManager.getClass())); + Query q = sharedEntityManager.createQuery("select p from Person as p"); + List people = q.getResultList(); + + assertTrue("Should be open to start with", sharedEntityManager.isOpen()); + sharedEntityManager.close(); + assertTrue("Close should have been silently ignored", sharedEntityManager.isOpen()); + } + + @ExpectedException(RuntimeException.class) + public void testBogusQuery() { + Query query = sharedEntityManager.createQuery("It's raining toads"); + // required in OpenJPA case + query.executeUpdate(); + } + + @ExpectedException(EntityNotFoundException.class) + public void testGetReferenceWhenNoRow() { + // Fails here with TopLink + Person notThere = sharedEntityManager.getReference(Person.class, 666); + + // We may get here (as with Hibernate). + // Either behaviour is + // valid--throw exception on first access + // or on getReference itself + notThere.getFirstName(); + } + + public void testLazyLoading() { + try { + Person tony = new Person(); + tony.setFirstName("Tony"); + tony.setLastName("Blair"); + tony.setDriversLicense(new DriversLicense("8439DK")); + sharedEntityManager.persist(tony); + setComplete(); + endTransaction(); + + startNewTransaction(); + sharedEntityManager.clear(); + Person newTony = entityManagerFactory.createEntityManager().getReference(Person.class, tony.getId()); + assertNotSame(newTony, tony); + endTransaction(); + + assertNotNull(newTony.getDriversLicense()); + + newTony.getDriversLicense().getSerialNumber(); + } + finally { + deleteFromTables(new String[] { "person", "drivers_license" }); + //setComplete(); + } + } + + public void testMultipleResults() { + // Add with JDBC + String firstName = "Tony"; + insertPerson(firstName); + + assertTrue(Proxy.isProxyClass(sharedEntityManager.getClass())); + Query q = sharedEntityManager.createQuery("select p from Person as p"); + List people = q.getResultList(); + + assertEquals(1, people.size()); + assertEquals(firstName, people.get(0).getFirstName()); + } + + protected final void insertPerson(String firstName) { + String INSERT_PERSON = "INSERT INTO PERSON (ID, FIRST_NAME, LAST_NAME) VALUES (?, ?, ?)"; + simpleJdbcTemplate.update(INSERT_PERSON, 1, firstName, "Blair"); + } + + public void testEntityManagerProxyRejectsProgrammaticTxManagement() { + try { + sharedEntityManager.getTransaction(); + fail("Should not be able to create transactions on container managed EntityManager"); + } + catch (IllegalStateException ex) { + } + } + + public void testSharedEntityManagerProxyRejectsProgrammaticTxJoining() { + try { + sharedEntityManager.joinTransaction(); + fail("Should not be able to join transactions with container managed EntityManager"); + } + catch (IllegalStateException ex) { + } + } + +// public void testAspectJInjectionOfConfigurableEntity() { +// Person p = new Person(); +// System.err.println(p); +// assertNotNull("Was injected", p.getTestBean()); +// assertEquals("Ramnivas", p.getTestBean().getName()); +// } + + public void testInstantiateAndSaveWithSharedEmProxy() { + testInstantiateAndSave(sharedEntityManager); + } + + protected void testInstantiateAndSave(EntityManager em) { + assertEquals("Should be no people from previous transactions", + 0, countRowsInTable("person")); + Person p = new Person(); + p.setFirstName("Tony"); + p.setLastName("Blair"); + em.persist(p); + + em.flush(); + assertEquals("1 row must have been inserted", 1, countRowsInTable("person")); + } + + public void testQueryNoPersons() { + EntityManager em = entityManagerFactory.createEntityManager(); + Query q = em.createQuery("select p from Person as p"); + List people = q.getResultList(); + assertEquals(0, people.size()); + try { + assertNull(q.getSingleResult()); + fail("Should have thrown NoResultException"); + } + catch (NoResultException ex) { + // expected + } + } + + @NotTransactional + public void testQueryNoPersonsNotTransactional() { + EntityManager em = entityManagerFactory.createEntityManager(); + Query q = em.createQuery("select p from Person as p"); + List people = q.getResultList(); + assertEquals(0, people.size()); + try { + assertNull(q.getSingleResult()); + fail("Should have thrown NoResultException"); + } + catch (NoResultException ex) { + // expected + } + } + + public void testQueryNoPersonsShared() { + EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(entityManagerFactory); + Query q = em.createQuery("select p from Person as p"); + q.setFlushMode(FlushModeType.AUTO); + List people = q.getResultList(); + try { + assertNull(q.getSingleResult()); + fail("Should have thrown NoResultException"); + } + catch (NoResultException ex) { + // expected + } + } + + @NotTransactional + public void testQueryNoPersonsSharedNotTransactional() { + EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(entityManagerFactory); + Query q = em.createQuery("select p from Person as p"); + q.setFlushMode(FlushModeType.AUTO); + List people = q.getResultList(); + assertEquals(0, people.size()); + try { + assertNull(q.getSingleResult()); + fail("Should have thrown IllegalStateException"); + } + catch (Exception ex) { + // IllegalStateException expected, but PersistenceException thrown by Hibernate + assertTrue(ex.getMessage().indexOf("closed") != -1); + } + q = em.createQuery("select p from Person as p"); + q.setFlushMode(FlushModeType.AUTO); + try { + assertNull(q.getSingleResult()); + fail("Should have thrown NoResultException"); + } + catch (NoResultException ex) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBeanTests.java new file mode 100644 index 00000000000..f4e65122676 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBeanTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa; + +import javax.persistence.EntityManagerFactory; +import javax.persistence.PersistenceException; +import javax.persistence.spi.PersistenceUnitInfo; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * Superclass for unit tests for EntityManagerFactory-creating beans. + * Note: Subclasses must set expectations on the mock EntityManagerFactory. + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +public abstract class AbstractEntityManagerFactoryBeanTests extends TestCase { + + protected static MockControl emfMc; + + protected static EntityManagerFactory mockEmf; + + + @Override + protected void setUp() throws Exception { + emfMc = MockControl.createControl(EntityManagerFactory.class); + mockEmf = (EntityManagerFactory) emfMc.getMock(); + } + + protected void checkInvariants(AbstractEntityManagerFactoryBean demf) { + assertTrue(EntityManagerFactory.class.isAssignableFrom(demf.getObjectType())); + Object gotObject = demf.getObject(); + assertTrue("Object created by factory implements EntityManagerFactoryInfo", + gotObject instanceof EntityManagerFactoryInfo); + EntityManagerFactoryInfo emfi = (EntityManagerFactoryInfo) demf.getObject(); + assertSame("Successive invocations of getObject() return same object", emfi, demf.getObject()); + assertSame(emfi, demf.getObject()); + assertSame(emfi.getNativeEntityManagerFactory(), mockEmf); + } + + @Override + protected void tearDown() throws Exception { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + } + + + protected static class DummyEntityManagerFactoryBean extends AbstractEntityManagerFactoryBean { + + private final EntityManagerFactory emf; + + public DummyEntityManagerFactoryBean(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + protected EntityManagerFactory createNativeEntityManagerFactory() throws PersistenceException { + return emf; + } + + public PersistenceUnitInfo getPersistenceUnitInfo() { + throw new UnsupportedOperationException(); + } + + public String getPersistenceUnitName() { + return "test"; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryIntegrationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryIntegrationTests.java new file mode 100644 index 00000000000..e453aad9b53 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryIntegrationTests.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa; + +import org.springframework.test.jpa.AbstractJpaTests; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public abstract class AbstractEntityManagerFactoryIntegrationTests extends AbstractJpaTests { + + public static final String[] TOPLINK_CONFIG_LOCATIONS = new String[] { + "/org/springframework/orm/jpa/toplink/toplink-manager.xml", "/org/springframework/orm/jpa/memdb.xml", + "/org/springframework/orm/jpa/inject.xml"}; + + public static final String[] ECLIPSELINK_CONFIG_LOCATIONS = new String[] { + "/org/springframework/orm/jpa/eclipselink/eclipselink-manager.xml", "/org/springframework/orm/jpa/memdb.xml", + "/org/springframework/orm/jpa/inject.xml"}; + + public static final String[] HIBERNATE_CONFIG_LOCATIONS = new String[] { + "/org/springframework/orm/jpa/hibernate/hibernate-manager.xml", "/org/springframework/orm/jpa/memdb.xml", + "/org/springframework/orm/jpa/inject.xml"}; + + public static final String[] OPENJPA_CONFIG_LOCATIONS = new String[] { + "/org/springframework/orm/jpa/openjpa/openjpa-manager.xml", "/org/springframework/orm/jpa/memdb.xml", + "/org/springframework/orm/jpa/inject.xml"}; + + + public static Provider getProvider() { + String provider = System.getProperty("org.springframework.orm.jpa.provider"); + if (provider != null) { + if (provider.toLowerCase().contains("eclipselink")) { + return Provider.ECLIPSELINK; + } + if (provider.toLowerCase().contains("hibernate")) { + return Provider.HIBERNATE; + } + if (provider.toLowerCase().contains("openjpa")) { + return Provider.OPENJPA; + } + } + return Provider.TOPLINK; + } + + + @Override + protected String getActualOrmXmlLocation() { + // Specify that we do NOT want to find such a file. + return null; + } + + protected String[] getConfigLocations() { + Provider provider = getProvider(); + switch (provider) { + case HIBERNATE: + return HIBERNATE_CONFIG_LOCATIONS; + case TOPLINK: + return TOPLINK_CONFIG_LOCATIONS; + case OPENJPA: + return OPENJPA_CONFIG_LOCATIONS; + default: + throw new IllegalStateException("Unknown provider: " + provider); + } + } + + @Override + protected void onTearDownAfterTransaction() throws Exception { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + } + + + public enum Provider { + TOPLINK, ECLIPSELINK, HIBERNATE, OPENJPA + }; + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/ApplicationManagedEntityManagerIntegrationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/ApplicationManagedEntityManagerIntegrationTests.java new file mode 100644 index 00000000000..2ba03fd14f5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/ApplicationManagedEntityManagerIntegrationTests.java @@ -0,0 +1,165 @@ +/* + * Copyright 2002-2006 the original author 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.orm.jpa; + +import java.util.List; +import java.lang.reflect.Proxy; + +import javax.persistence.EntityManager; +import javax.persistence.Query; +import javax.persistence.TransactionRequiredException; + +import org.springframework.aop.support.AopUtils; +import org.springframework.orm.jpa.domain.Person; +import org.springframework.orm.jpa.AbstractEntityManagerFactoryIntegrationTests; +import org.springframework.test.annotation.NotTransactional; +import org.springframework.transaction.annotation.Transactional; + +/** + * An application-managed entity manager can join an existing transaction, + * but such joining must be made programmatically, not transactionally. + * + * @author Rod Johnson + * @since 2.0 + */ +public class ApplicationManagedEntityManagerIntegrationTests extends AbstractEntityManagerFactoryIntegrationTests { + + @NotTransactional + public void testEntityManagerIsProxy() { + assertTrue("EntityManagerFactory is proxied", Proxy.isProxyClass(entityManagerFactory.getClass())); + } + + @Transactional(readOnly=true) + public void testEntityManagerProxyIsProxy() { + EntityManager em = entityManagerFactory.createEntityManager(); + assertTrue(Proxy.isProxyClass(em.getClass())); + Query q = em.createQuery("select p from Person as p"); + List people = q.getResultList(); + + assertTrue("Should be open to start with", em.isOpen()); + em.close(); + assertFalse("Close should work on application managed EM", em.isOpen()); + } + + public void testEntityManagerProxyAcceptsProgrammaticTxJoining() { + EntityManager em = entityManagerFactory.createEntityManager(); + em.joinTransaction(); + } + + public void testInstantiateAndSave() { + EntityManager em = entityManagerFactory.createEntityManager(); + em.joinTransaction(); + doInstantiateAndSave(em); + } + + public void testCannotFlushWithoutGettingTransaction() { + EntityManager em = entityManagerFactory.createEntityManager(); + try { + doInstantiateAndSave(em); + fail("Should have thrown TransactionRequiredException"); + } + catch (TransactionRequiredException ex) { + // expected + } + + // TODO following lines are a workaround for Hibernate bug + // If Hibernate throws an exception due to flush(), + // it actually HAS flushed, meaning that the database + // was updated outside the transaction + deleteAllPeopleUsingEntityManager(sharedEntityManager); + setComplete(); + } + + public void doInstantiateAndSave(EntityManager em) { + testStateClean(); + Person p = new Person(); + + p.setFirstName("Tony"); + p.setLastName("Blair"); + em.persist(p); + + em.flush(); + assertEquals("1 row must have been inserted", + 1, countRowsInTable("person")); + } + + public void testStateClean() { + assertEquals("Should be no people from previous transactions", + 0, countRowsInTable("person")); + } + + public void testReuseInNewTransaction() { + EntityManager em = entityManagerFactory.createEntityManager(); + em.joinTransaction(); + + doInstantiateAndSave(em); + endTransaction(); + + assertFalse(em.getTransaction().isActive()); + + startNewTransaction(); + // Call any method: should cause automatic tx invocation + assertFalse(em.contains(new Person())); + + assertFalse(em.getTransaction().isActive()); + em.joinTransaction(); + + assertTrue(em.getTransaction().isActive()); + + doInstantiateAndSave(em); + setComplete(); + endTransaction(); // Should rollback + assertEquals("Tx must have committed back", + 1, countRowsInTable("person")); + + // Now clean up the database + startNewTransaction(); + em.joinTransaction(); + deleteAllPeopleUsingEntityManager(em); + assertEquals("People have been killed", + 0, countRowsInTable("person")); + setComplete(); + } + + public static void deleteAllPeopleUsingEntityManager(EntityManager em) { + em.createQuery("delete from Person p").executeUpdate(); + } + + public void testRollbackOccurs() { + EntityManager em = entityManagerFactory.createEntityManager(); + em.joinTransaction(); + doInstantiateAndSave(em); + endTransaction(); // Should rollback + assertEquals("Tx must have been rolled back", + 0, countRowsInTable("person")); + } + + public void testCommitOccurs() { + EntityManager em = entityManagerFactory.createEntityManager(); + em.joinTransaction(); + doInstantiateAndSave(em); + + setComplete(); + endTransaction(); // Should rollback + assertEquals("Tx must have committed back", + 1, countRowsInTable("person")); + + // Now clean up the database + deleteFromTables(new String[] { "person" }); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/ContainerManagedEntityManagerIntegrationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/ContainerManagedEntityManagerIntegrationTests.java new file mode 100644 index 00000000000..15845f6453c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/ContainerManagedEntityManagerIntegrationTests.java @@ -0,0 +1,178 @@ +/* + * Copyright 2002-2006 the original author 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.orm.jpa; + +import java.util.List; +import java.lang.reflect.Proxy; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceException; +import javax.persistence.Query; +import javax.persistence.TransactionRequiredException; + +import org.springframework.aop.support.AopUtils; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.support.PersistenceExceptionTranslator; +import org.springframework.orm.jpa.domain.Person; +import org.springframework.test.annotation.ExpectedException; +import org.springframework.test.annotation.NotTransactional; + +/** + * Integration tests using in-memory database for container-managed JPA + * + * @author Rod Johnson + * @since 2.0 + */ +public class ContainerManagedEntityManagerIntegrationTests extends AbstractEntityManagerFactoryIntegrationTests { + + @NotTransactional + public void testExceptionTranslationWithDialectFoundOnIntroducedEntityManagerInfo() throws Exception { + doTestExceptionTranslationWithDialectFound(((EntityManagerFactoryInfo) entityManagerFactory).getJpaDialect()); + } + + @NotTransactional + public void testExceptionTranslationWithDialectFoundOnEntityManagerFactoryBean() throws Exception { + AbstractEntityManagerFactoryBean aefb = + (AbstractEntityManagerFactoryBean) applicationContext.getBean("&entityManagerFactory"); + assertNotNull("Dialect must have been set", aefb.getJpaDialect()); + doTestExceptionTranslationWithDialectFound(aefb); + } + + protected void doTestExceptionTranslationWithDialectFound(PersistenceExceptionTranslator pet) throws Exception { + RuntimeException in1 = new RuntimeException("in1"); + PersistenceException in2 = new PersistenceException(); + assertNull("No translation here", pet.translateExceptionIfPossible(in1)); + DataAccessException dex = pet.translateExceptionIfPossible(in2); + assertNotNull(dex); + assertSame(in2, dex.getCause()); + } + + public void testEntityManagerProxyIsProxy() { + EntityManager em = createContainerManagedEntityManager(); + assertTrue(Proxy.isProxyClass(em.getClass())); + Query q = em.createQuery("select p from Person as p"); + List people = q.getResultList(); + assertTrue(people.isEmpty()); + + assertTrue("Should be open to start with", em.isOpen()); + try { + em.close(); + fail("Close should not work on container managed EM"); + } + catch (IllegalStateException ex) { + // Ok + } + assertTrue(em.isOpen()); + } + + // This would be legal, at least if not actually _starting_ a tx + @ExpectedException(IllegalStateException.class) + public void testEntityManagerProxyRejectsProgrammaticTxManagement() { + createContainerManagedEntityManager().getTransaction(); + } + + /* + * See comments in spec on EntityManager.joinTransaction(). + * We take the view that this is a valid no op. + */ + public void testContainerEntityManagerProxyAllowsJoinTransactionInTransaction() { + createContainerManagedEntityManager().joinTransaction(); + } + + @NotTransactional + @ExpectedException(TransactionRequiredException.class) + public void testContainerEntityManagerProxyRejectsJoinTransactionWithoutTransaction() { + createContainerManagedEntityManager().joinTransaction(); + } + + public void testInstantiateAndSave() { + EntityManager em = createContainerManagedEntityManager(); + doInstantiateAndSave(em); + } + + public void doInstantiateAndSave(EntityManager em) { + assertEquals("Should be no people from previous transactions", + 0, countRowsInTable("person")); + Person p = new Person(); + + p.setFirstName("Tony"); + p.setLastName("Blair"); + em.persist(p); + + em.flush(); + assertEquals("1 row must have been inserted", + 1, countRowsInTable("person")); + } + + public void testReuseInNewTransaction() { + EntityManager em = createContainerManagedEntityManager(); + doInstantiateAndSave(em); + endTransaction(); + + //assertFalse(em.getTransaction().isActive()); + + startNewTransaction(); + // Call any method: should cause automatic tx invocation + assertFalse(em.contains(new Person())); + //assertTrue(em.getTransaction().isActive()); + + doInstantiateAndSave(em); + setComplete(); + endTransaction(); // Should rollback + assertEquals("Tx must have committed back", + 1, countRowsInTable("person")); + + // Now clean up the database + deleteFromTables(new String[] { "person" }); + } + + public void testRollbackOccurs() { + EntityManager em = createContainerManagedEntityManager(); + doInstantiateAndSave(em); + endTransaction(); // Should rollback + assertEquals("Tx must have been rolled back", + 0, countRowsInTable("person")); + } + + public void testCommitOccurs() { + EntityManager em = createContainerManagedEntityManager(); + doInstantiateAndSave(em); + setComplete(); + endTransaction(); // Should rollback + assertEquals("Tx must have committed back", + 1, countRowsInTable("person")); + + // Now clean up the database + deleteFromTables(new String[] { "person" }); + } + + /* + * TODO: This displays incorrect behavior in TopLink because of its EJBQLException - + * which is not a subclass of PersistenceException but rather of TopLinkException! + public void testEntityManagerProxyException() { + EntityManager em = entityManagerFactory.createEntityManager(); + try { + em.createQuery("select p from Person p where p.o=0").getResultList(); + fail("Semantic nonsense should be rejected"); + } + catch (PersistenceException ex) { + // expected + } + } + */ + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/DefaultJpaDialectTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/DefaultJpaDialectTests.java new file mode 100644 index 00000000000..5135a401fdb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/DefaultJpaDialectTests.java @@ -0,0 +1,85 @@ +/* + * Copyright 2002-2006 the original author 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.orm.jpa; + +import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; +import javax.persistence.OptimisticLockException; + +import junit.framework.TestCase; + +import org.easymock.MockControl; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; +import org.springframework.transaction.support.DefaultTransactionDefinition; + +/** + * + * @author Costin Leau + * + */ +public class DefaultJpaDialectTests extends TestCase { + JpaDialect dialect; + + protected void setUp() throws Exception { + dialect = new DefaultJpaDialect(); + } + + protected void tearDown() throws Exception { + dialect = null; + } + + public void testDefaultTransactionDefinition() throws Exception { + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + definition.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ); + + try { + dialect.beginTransaction(null, definition); + fail("expected exception"); + } + catch (TransactionException e) { + // ok + } + } + + public void testDefaultBeginTransaction() throws Exception { + TransactionDefinition definition = new DefaultTransactionDefinition(); + MockControl entityControl = MockControl.createControl(EntityManager.class); + EntityManager entityManager = (EntityManager) entityControl.getMock(); + + MockControl txControl = MockControl.createControl(EntityTransaction.class); + EntityTransaction entityTx = (EntityTransaction) txControl.getMock(); + + entityControl.expectAndReturn(entityManager.getTransaction(), entityTx); + entityTx.begin(); + + entityControl.replay(); + txControl.replay(); + + dialect.beginTransaction(entityManager, definition); + + entityControl.verify(); + txControl.verify(); + } + + public void testTranslateException() { + OptimisticLockException ex = new OptimisticLockException(); + assertEquals( + EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(ex).getCause(), + dialect.translateExceptionIfPossible(ex).getCause()); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/EntityManagerFactoryBeanSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/EntityManagerFactoryBeanSupportTests.java new file mode 100644 index 00000000000..9ad43e6e7f8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/EntityManagerFactoryBeanSupportTests.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2006 the original author 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.orm.jpa; + +/** + * @author Rod Johnson + */ +public class EntityManagerFactoryBeanSupportTests extends AbstractEntityManagerFactoryBeanTests { + + @Override + protected void setUp() throws Exception { + super.setUp(); + mockEmf.close(); + emfMc.setVoidCallable(); + emfMc.replay(); + } + + public void testHookIsCalled() throws Exception { + DummyEntityManagerFactoryBean demf = new DummyEntityManagerFactoryBean(mockEmf); + + demf.afterPropertiesSet(); + + checkInvariants(demf); + + // Should trigger close method expected by EntityManagerFactory mock + demf.destroy(); + + emfMc.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/EntityManagerFactoryUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/EntityManagerFactoryUtilsTests.java new file mode 100644 index 00000000000..e3b323ab35d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/EntityManagerFactoryUtilsTests.java @@ -0,0 +1,154 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa; + +import javax.persistence.EntityExistsException; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityNotFoundException; +import javax.persistence.NoResultException; +import javax.persistence.NonUniqueResultException; +import javax.persistence.OptimisticLockException; +import javax.persistence.PersistenceException; +import javax.persistence.TransactionRequiredException; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Costin Leau + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class EntityManagerFactoryUtilsTests extends TestCase { + + /* + * Test method for + * 'org.springframework.orm.jpa.EntityManagerFactoryUtils.doGetEntityManager(EntityManagerFactory)' + */ + public void testDoGetEntityManager() { + // test null assertion + try { + EntityManagerFactoryUtils.doGetTransactionalEntityManager(null, null); + fail("expected exception"); + } + catch (IllegalArgumentException ex) { + // it's okay + } + MockControl mockControl = MockControl.createControl(EntityManagerFactory.class); + EntityManagerFactory factory = (EntityManagerFactory) mockControl.getMock(); + + mockControl.replay(); + // no tx active + assertNull(EntityManagerFactoryUtils.doGetTransactionalEntityManager(factory, null)); + mockControl.verify(); + + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + } + + public void testDoGetEntityManagerWithTx() throws Exception { + try { + MockControl mockControl = MockControl.createControl(EntityManagerFactory.class); + EntityManagerFactory factory = (EntityManagerFactory) mockControl.getMock(); + + MockControl managerControl = MockControl.createControl(EntityManager.class); + EntityManager manager = (EntityManager) managerControl.getMock(); + + TransactionSynchronizationManager.initSynchronization(); + mockControl.expectAndReturn(factory.createEntityManager(), manager); + + mockControl.replay(); + // no tx active + assertSame(manager, EntityManagerFactoryUtils.doGetTransactionalEntityManager(factory, null)); + assertSame(manager, ((EntityManagerHolder)TransactionSynchronizationManager.unbindResource(factory)).getEntityManager()); + + mockControl.verify(); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + } + + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + } + + public void testTranslatesIllegalStateException() { + IllegalStateException ise = new IllegalStateException(); + DataAccessException dex = EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(ise); + assertSame(ise, dex.getCause()); + assertTrue(dex instanceof InvalidDataAccessApiUsageException); + } + + public void testTranslatesIllegalArgumentException() { + IllegalArgumentException iae = new IllegalArgumentException(); + DataAccessException dex = EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(iae); + assertSame(iae, dex.getCause()); + assertTrue(dex instanceof InvalidDataAccessApiUsageException); + } + + /** + * We do not convert unknown exceptions. They may result from user code. + */ + public void testDoesNotTranslateUnfamiliarException() { + UnsupportedOperationException userRuntimeException = new UnsupportedOperationException(); + assertNull( + "Exception should not be wrapped", + EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(userRuntimeException)); + } + + /* + * Test method for + * 'org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessException(PersistenceException)' + */ + public void testConvertJpaPersistenceException() { + EntityNotFoundException entityNotFound = new EntityNotFoundException(); + assertSame(JpaObjectRetrievalFailureException.class, + EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(entityNotFound).getClass()); + + NoResultException noResult = new NoResultException(); + assertSame(EmptyResultDataAccessException.class, + EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(noResult).getClass()); + + NonUniqueResultException nonUniqueResult = new NonUniqueResultException(); + assertSame(IncorrectResultSizeDataAccessException.class, + EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(nonUniqueResult).getClass()); + + OptimisticLockException optimisticLock = new OptimisticLockException(); + assertSame(JpaOptimisticLockingFailureException.class, + EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(optimisticLock).getClass()); + + EntityExistsException entityExists = new EntityExistsException("foo"); + assertSame(DataIntegrityViolationException.class, + EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(entityExists).getClass()); + + TransactionRequiredException transactionRequired = new TransactionRequiredException("foo"); + assertSame(InvalidDataAccessApiUsageException.class, + EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(transactionRequired).getClass()); + + PersistenceException unknown = new PersistenceException() { + }; + assertSame(JpaSystemException.class, + EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(unknown).getClass()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/JpaInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/JpaInterceptorTests.java new file mode 100644 index 00000000000..6075c524d39 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/JpaInterceptorTests.java @@ -0,0 +1,300 @@ +/* + * Copyright 2002-2006 the original author 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.orm.jpa; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Method; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.PersistenceException; + +import junit.framework.TestCase; +import org.aopalliance.intercept.Interceptor; +import org.aopalliance.intercept.Invocation; +import org.aopalliance.intercept.MethodInvocation; +import org.easymock.MockControl; + +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Costin Leau + */ +public class JpaInterceptorTests extends TestCase { + + private MockControl factoryControl, managerControl; + + private EntityManagerFactory factory; + + private EntityManager entityManager; + + + @Override + protected void setUp() throws Exception { + factoryControl = MockControl.createControl(EntityManagerFactory.class); + factory = (EntityManagerFactory) factoryControl.getMock(); + managerControl = MockControl.createControl(EntityManager.class); + entityManager = (EntityManager) managerControl.getMock(); + } + + @Override + protected void tearDown() throws Exception { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl = null; + factory = null; + managerControl = null; + entityManager = null; + + } + + public void testInterceptorWithNewEntityManager() throws PersistenceException { + factoryControl.expectAndReturn(factory.createEntityManager(), entityManager); + entityManager.close(); + + factoryControl.replay(); + managerControl.replay(); + + JpaInterceptor interceptor = new JpaInterceptor(); + interceptor.setEntityManagerFactory(factory); + try { + interceptor.invoke(new TestInvocation(factory)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + + factoryControl.verify(); + managerControl.verify(); + } + + public void testInterceptorWithNewEntityManagerAndLazyFlush() throws PersistenceException { + factoryControl.expectAndReturn(factory.createEntityManager(), entityManager); + entityManager.close(); + + factoryControl.replay(); + managerControl.replay(); + + JpaInterceptor interceptor = new JpaInterceptor(); + interceptor.setFlushEager(false); + interceptor.setEntityManagerFactory(factory); + try { + interceptor.invoke(new TestInvocation(factory)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + + factoryControl.verify(); + managerControl.verify(); + } + + public void testInterceptorWithThreadBound() { + factoryControl.replay(); + managerControl.replay(); + + TransactionSynchronizationManager.bindResource(factory, new EntityManagerHolder(entityManager)); + JpaInterceptor interceptor = new JpaInterceptor(); + interceptor.setEntityManagerFactory(factory); + try { + interceptor.invoke(new TestInvocation(factory)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + finally { + TransactionSynchronizationManager.unbindResource(factory); + } + + factoryControl.verify(); + managerControl.verify(); + } + + public void testInterceptorWithThreadBoundAndFlushEager() throws PersistenceException { + //entityManager.setFlushMode(FlushModeType.AUTO); + entityManager.flush(); + + factoryControl.replay(); + managerControl.replay(); + + TransactionSynchronizationManager.bindResource(factory, new EntityManagerHolder(entityManager)); + JpaInterceptor interceptor = new JpaInterceptor(); + interceptor.setFlushEager(true); + interceptor.setEntityManagerFactory(factory); + try { + interceptor.invoke(new TestInvocation(factory)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + finally { + TransactionSynchronizationManager.unbindResource(factory); + } + + factoryControl.verify(); + managerControl.verify(); + } + + public void testInterceptorWithThreadBoundAndFlushCommit() { + //entityManager.setFlushMode(FlushModeType.COMMIT); + //entityManager.flush(); + + factoryControl.replay(); + managerControl.replay(); + + TransactionSynchronizationManager.bindResource(factory, new EntityManagerHolder(entityManager)); + JpaInterceptor interceptor = new JpaInterceptor(); + interceptor.setFlushEager(false); + interceptor.setEntityManagerFactory(factory); + try { + interceptor.invoke(new TestInvocation(factory)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + finally { + TransactionSynchronizationManager.unbindResource(factory); + } + + factoryControl.verify(); + managerControl.verify(); + } + + public void testInterceptorWithFlushFailure() throws Throwable { + factoryControl.expectAndReturn(factory.createEntityManager(), entityManager); + entityManager.flush(); + + PersistenceException exception = new PersistenceException(); + managerControl.setThrowable(exception, 1); + entityManager.close(); + + factoryControl.replay(); + managerControl.replay(); + + JpaInterceptor interceptor = new JpaInterceptor(); + interceptor.setFlushEager(true); + interceptor.setEntityManagerFactory(factory); + try { + interceptor.invoke(new TestInvocation(factory)); + //fail("Should have thrown JpaSystemException"); + } + catch (JpaSystemException ex) { + // expected + assertEquals(exception, ex.getCause()); + } + + factoryControl.verify(); + managerControl.verify(); + } + + public void testInterceptorWithFlushFailureWithoutConversion() throws Throwable { + factoryControl.expectAndReturn(factory.createEntityManager(), entityManager); + entityManager.flush(); + + PersistenceException exception = new PersistenceException(); + managerControl.setThrowable(exception, 1); + entityManager.close(); + + factoryControl.replay(); + managerControl.replay(); + + JpaInterceptor interceptor = new JpaInterceptor(); + interceptor.setFlushEager(true); + interceptor.setExceptionConversionEnabled(false); + interceptor.setEntityManagerFactory(factory); + try { + interceptor.invoke(new TestInvocation(factory)); + //fail("Should have thrown JpaSystemException"); + } + catch (PersistenceException ex) { + // expected + assertEquals(exception, ex); + } + + factoryControl.verify(); + managerControl.verify(); + } + + + private static class TestInvocation implements MethodInvocation { + + private EntityManagerFactory entityManagerFactory; + + public TestInvocation(EntityManagerFactory entityManagerFactory) { + this.entityManagerFactory = entityManagerFactory; + } + + public Object proceed() throws Throwable { + if (!TransactionSynchronizationManager.hasResource(this.entityManagerFactory)) { + throw new IllegalStateException("Session not bound"); + } + return null; + } + + public int getCurrentInterceptorIndex() { + return 0; + } + + public int getNumberOfInterceptors() { + return 0; + } + + public Interceptor getInterceptor(int i) { + return null; + } + + public Method getMethod() { + return null; + } + + public AccessibleObject getStaticPart() { + return null; + } + + public Object getArgument(int i) { + return null; + } + + public Object[] getArguments() { + return null; + } + + public void setArgument(int i, Object handler) { + } + + public int getArgumentCount() { + return 0; + } + + public Object getThis() { + return null; + } + + public Object getProxy() { + return null; + } + + public Invocation cloneInstance() { + return null; + } + + public void release() { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/JpaTemplateTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/JpaTemplateTests.java new file mode 100644 index 00000000000..60386d548c6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/JpaTemplateTests.java @@ -0,0 +1,521 @@ +/* + * Copyright 2002-2006 the original author 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.orm.jpa; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.PersistenceException; +import javax.persistence.Query; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.dao.DataAccessException; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Costin Leau + */ +public class JpaTemplateTests extends TestCase { + + private JpaTemplate template; + + private MockControl factoryControl, managerControl; + + private EntityManager manager; + + private EntityManagerFactory factory; + + protected void setUp() throws Exception { + template = new JpaTemplate(); + + factoryControl = MockControl.createControl(EntityManagerFactory.class); + factory = (EntityManagerFactory) factoryControl.getMock(); + managerControl = MockControl.createControl(EntityManager.class); + manager = (EntityManager) managerControl.getMock(); + + template.setEntityManager(manager); + template.afterPropertiesSet(); + + } + + protected void tearDown() throws Exception { + template = null; + factoryControl = null; + managerControl = null; + manager = null; + factory = null; + } + + /* + * Test method for + * 'org.springframework.orm.jpa.JpaTemplate.JpaTemplate(EntityManagerFactory)' + */ + public void testJpaTemplateEntityManagerFactory() { + + } + + /* + * Test method for + * 'org.springframework.orm.jpa.JpaTemplate.JpaTemplate(EntityManager)' + */ + public void testJpaTemplateEntityManager() { + + } + + /* + * Test method for + * 'org.springframework.orm.jpa.JpaTemplate.execute(JpaCallback)' + */ + public void testExecuteJpaCallback() { + template.setExposeNativeEntityManager(true); + template.setEntityManager(manager); + template.afterPropertiesSet(); + + managerControl.replay(); + factoryControl.replay(); + + template.execute(new JpaCallback() { + + public Object doInJpa(EntityManager em) throws PersistenceException { + assertSame(em, manager); + return null; + } + }); + + template.setExposeNativeEntityManager(false); + template.execute(new JpaCallback() { + + public Object doInJpa(EntityManager em) throws PersistenceException { + assertNotSame(em, manager); + return null; + } + }); + managerControl.verify(); + factoryControl.verify(); + } + + /* + * Test method for + * 'org.springframework.orm.jpa.JpaTemplate.executeFind(JpaCallback)' + */ + public void testExecuteFind() { + template.setEntityManager(manager); + template.setExposeNativeEntityManager(true); + template.afterPropertiesSet(); + + managerControl.replay(); + factoryControl.replay(); + + try { + template.executeFind(new JpaCallback() { + + public Object doInJpa(EntityManager em) throws PersistenceException { + assertSame(em, manager); + return new Object(); + } + }); + fail("should have thrown exception"); + } + catch (DataAccessException e) { + // expected + } + + managerControl.verify(); + factoryControl.verify(); + } + + /* + * Test method for + * 'org.springframework.orm.jpa.JpaTemplate.execute(JpaCallback, boolean)' + */ + public void testExecuteJpaCallbackBoolean() { + template = new JpaTemplate(); + template.setExposeNativeEntityManager(false); + template.setEntityManagerFactory(factory); + template.afterPropertiesSet(); + + factoryControl.expectAndReturn(factory.createEntityManager(), manager); + manager.close(); + + managerControl.replay(); + factoryControl.replay(); + + template.execute(new JpaCallback() { + + public Object doInJpa(EntityManager em) throws PersistenceException { + assertSame(em, manager); + return null; + } + }, true); + + managerControl.verify(); + factoryControl.verify(); + } + + public void testExecuteJpaCallbackBooleanWithPrebound() { + template.setExposeNativeEntityManager(false); + template.setEntityManagerFactory(factory); + template.afterPropertiesSet(); + + TransactionSynchronizationManager.bindResource(factory, new EntityManagerHolder(manager)); + managerControl.replay(); + factoryControl.replay(); + + try { + template.execute(new JpaCallback() { + + public Object doInJpa(EntityManager em) throws PersistenceException { + assertSame(em, manager); + return null; + } + }, true); + + managerControl.verify(); + factoryControl.verify(); + } + finally { + TransactionSynchronizationManager.unbindResource(factory); + } + } + + /* + * Test method for + * 'org.springframework.orm.jpa.JpaTemplate.createSharedEntityManager(EntityManager)' + */ + public void testCreateEntityManagerProxy() { + manager.clear(); + managerControl.replay(); + + EntityManager proxy = template.createEntityManagerProxy(manager); + assertNotSame(manager, proxy); + assertFalse(manager.equals(proxy)); + assertFalse(manager.hashCode() == proxy.hashCode()); + // close call not propagated to the em + proxy.close(); + proxy.clear(); + + managerControl.verify(); + } + + /* + * Test method for 'org.springframework.orm.jpa.JpaTemplate.find(Class, + * Object) ' + */ + public void testFindClassOfTObject() { + Integer result = new Integer(1); + Object id = new Object(); + managerControl.expectAndReturn(manager.find(Number.class, id), result); + managerControl.replay(); + factoryControl.replay(); + + assertSame(result, template.find(Number.class, id)); + + managerControl.verify(); + factoryControl.verify(); + } + + /* + * Test method for + * 'org.springframework.orm.jpa.JpaTemplate.getReference(Class, Object) + * ' + */ + public void testGetReference() { + Integer reference = new Integer(1); + Object id = new Object(); + managerControl.expectAndReturn(manager.getReference(Number.class, id), reference); + managerControl.replay(); + factoryControl.replay(); + + assertSame(reference, template.getReference(Number.class, id)); + + managerControl.verify(); + factoryControl.verify(); + } + + /* + * Test method for + * 'org.springframework.orm.jpa.JpaTemplate.contains(Object)' + */ + public void testContains() { + boolean result = true; + Object entity = new Object(); + managerControl.expectAndReturn(manager.contains(entity), result); + managerControl.replay(); + factoryControl.replay(); + + assertSame(result, template.contains(entity)); + + managerControl.verify(); + factoryControl.verify(); + } + + /* + * Test method for 'org.springframework.orm.jpa.JpaTemplate.refresh(Object)' + */ + public void testRefresh() { + Object entity = new Object(); + manager.refresh(entity); + managerControl.replay(); + factoryControl.replay(); + + template.refresh(entity); + + managerControl.verify(); + factoryControl.verify(); + } + + /* + * Test method for 'org.springframework.orm.jpa.JpaTemplate.persist(Object)' + */ + public void testPersist() { + Object entity = new Object(); + manager.persist(entity); + managerControl.replay(); + factoryControl.replay(); + + template.persist(entity); + + managerControl.verify(); + factoryControl.verify(); + } + + /* + * Test method for 'org.springframework.orm.jpa.JpaTemplate.merge(T) ' + */ + public void testMerge() { + Object result = new Object(); + Object entity = new Object(); + managerControl.expectAndReturn(manager.merge(entity), result); + managerControl.replay(); + factoryControl.replay(); + + assertSame(result, template.merge(entity)); + + managerControl.verify(); + factoryControl.verify(); + } + + /* + * Test method for 'org.springframework.orm.jpa.JpaTemplate.remove(Object)' + */ + public void testRemove() { + Object entity = new Object(); + manager.remove(entity); + managerControl.replay(); + factoryControl.replay(); + + template.remove(entity); + + managerControl.verify(); + factoryControl.verify(); + } + + /* + * Test method for 'org.springframework.orm.jpa.JpaTemplate.flush()' + */ + public void testFlush() { + manager.flush(); + managerControl.replay(); + factoryControl.replay(); + + template.flush(); + + managerControl.verify(); + factoryControl.verify(); + } + + /* + * Test method for 'org.springframework.orm.jpa.JpaTemplate.find(String)' + */ + public void testFindString() { + String queryString = "some query"; + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + List result = new ArrayList(); + + managerControl.expectAndReturn(manager.createQuery(queryString), query); + queryControl.expectAndReturn(query.getResultList(), result); + + managerControl.replay(); + factoryControl.replay(); + queryControl.replay(); + + assertSame(result, template.find(queryString)); + + managerControl.verify(); + factoryControl.verify(); + queryControl.verify(); + } + + /* + * Test method for 'org.springframework.orm.jpa.JpaTemplate.find(String, + * Object...)' + */ + public void testFindStringObjectArray() { + String queryString = "some query"; + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + List result = new ArrayList(); + Object param1 = new Object(); + Object param2 = new Object(); + Object[] params = new Object[] { param1, param2 }; + + managerControl.expectAndReturn(manager.createQuery(queryString), query); + queryControl.expectAndReturn(query.setParameter(1, param1), null); + queryControl.expectAndReturn(query.setParameter(2, param2), null); + + queryControl.expectAndReturn(query.getResultList(), result); + + managerControl.replay(); + factoryControl.replay(); + queryControl.replay(); + + assertSame(result, template.find(queryString, params)); + + managerControl.verify(); + factoryControl.verify(); + queryControl.verify(); + } + + /* + * Test method for 'org.springframework.orm.jpa.JpaTemplate.find(String, Map)' + */ + public void testFindStringMapOfStringObject() { + String queryString = "some query"; + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + List result = new ArrayList(); + Object param1 = new Object(); + Object param2 = new Object(); + Map params = new HashMap(); + params.put("param1", param1); + params.put("param2", param2); + + managerControl.expectAndReturn(manager.createQuery(queryString), query); + queryControl.expectAndReturn(query.setParameter("param1", param1), null); + queryControl.expectAndReturn(query.setParameter("param2", param2), null); + + queryControl.expectAndReturn(query.getResultList(), result); + + managerControl.replay(); + factoryControl.replay(); + queryControl.replay(); + + assertSame(result, template.findByNamedParams(queryString, params)); + + managerControl.verify(); + factoryControl.verify(); + queryControl.verify(); + } + + /* + * Test method for + * 'org.springframework.orm.jpa.JpaTemplate.findByNamedQuery(String)' + */ + public void testFindByNamedQueryString() { + String queryName = "some query name"; + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + List result = new ArrayList(); + + managerControl.expectAndReturn(manager.createNamedQuery(queryName), query); + + queryControl.expectAndReturn(query.getResultList(), result); + + managerControl.replay(); + factoryControl.replay(); + queryControl.replay(); + + assertSame(result, template.findByNamedQuery(queryName)); + + managerControl.verify(); + factoryControl.verify(); + queryControl.verify(); + } + + /* + * Test method for + * 'org.springframework.orm.jpa.JpaTemplate.findByNamedQuery(String, + * Object...)' + */ + public void testFindByNamedQueryStringObjectArray() { + String queryName = "some query name"; + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + List result = new ArrayList(); + Object param1 = new Object(); + Object param2 = new Object(); + Object[] params = new Object[] { param1, param2 }; + + managerControl.expectAndReturn(manager.createNamedQuery(queryName), query); + queryControl.expectAndReturn(query.setParameter(1, param1), null); + queryControl.expectAndReturn(query.setParameter(2, param2), null); + + queryControl.expectAndReturn(query.getResultList(), result); + + managerControl.replay(); + factoryControl.replay(); + queryControl.replay(); + + assertSame(result, template.findByNamedQuery(queryName, params)); + + managerControl.verify(); + factoryControl.verify(); + queryControl.verify(); + } + + /* + * Test method for + * 'org.springframework.orm.jpa.JpaTemplate.findByNamedQuery(String, Map)' + */ + public void testFindByNamedQueryStringMapOfStringObject() { + String queryName = "some query name"; + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + List result = new ArrayList(); + Object param1 = new Object(); + Object param2 = new Object(); + Map params = new HashMap(); + params.put("param1", param1); + params.put("param2", param2); + + managerControl.expectAndReturn(manager.createNamedQuery(queryName), query); + queryControl.expectAndReturn(query.setParameter("param1", param1), null); + queryControl.expectAndReturn(query.setParameter("param2", param2), null); + + queryControl.expectAndReturn(query.getResultList(), result); + + managerControl.replay(); + factoryControl.replay(); + queryControl.replay(); + + assertSame(result, template.findByNamedQueryAndNamedParams(queryName, params)); + + managerControl.verify(); + factoryControl.verify(); + queryControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/JpaTransactionManagerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/JpaTransactionManagerTests.java new file mode 100644 index 00000000000..6888d84750f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/JpaTransactionManagerTests.java @@ -0,0 +1,1074 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityTransaction; +import javax.persistence.PersistenceException; +import javax.persistence.RollbackException; +import javax.sql.DataSource; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.transaction.InvalidIsolationLevelException; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.TransactionSystemException; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionSynchronizationAdapter; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * @author Costin Leau + * @author Juergen Hoeller + */ +public class JpaTransactionManagerTests extends TestCase { + + private MockControl factoryControl, managerControl, txControl; + + private EntityManager manager; + + private EntityTransaction tx; + + private EntityManagerFactory factory; + + private JpaTransactionManager transactionManager; + + private JpaTemplate template; + + private TransactionTemplate tt; + + + protected void setUp() throws Exception { + factoryControl = MockControl.createControl(EntityManagerFactory.class); + factory = (EntityManagerFactory) factoryControl.getMock(); + managerControl = MockControl.createControl(EntityManager.class); + manager = (EntityManager) managerControl.getMock(); + txControl = MockControl.createControl(EntityTransaction.class); + tx = (EntityTransaction) txControl.getMock(); + + transactionManager = new JpaTransactionManager(factory); + template = new JpaTemplate(factory); + template.afterPropertiesSet(); + tt = new TransactionTemplate(transactionManager); + + factoryControl.expectAndReturn(factory.createEntityManager(), manager); + managerControl.expectAndReturn(manager.getTransaction(), tx); + tx.begin(); + manager.close(); + } + + protected void tearDown() throws Exception { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + } + + + public void testTransactionCommit() { + managerControl.expectAndReturn(manager.getTransaction(), tx); + txControl.expectAndReturn(tx.getRollbackOnly(), false); + managerControl.expectAndReturn(manager.getTransaction(), tx); + tx.commit(); + manager.flush(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) { + em.flush(); + return l; + } + }); + } + }); + assertSame(l, result); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testTransactionCommitWithRollbackException() { + managerControl.expectAndReturn(manager.getTransaction(), tx); + txControl.expectAndReturn(tx.getRollbackOnly(), true); + managerControl.expectAndReturn(manager.getTransaction(), tx); + tx.commit(); + txControl.setThrowable(new RollbackException()); + manager.flush(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + try { + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) { + em.flush(); + return l; + } + }); + } + }); + assertSame(l, result); + } + catch (TransactionSystemException tse) { + // expected + assertTrue(tse.getCause() instanceof RollbackException); + } + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testTransactionRollback() { + managerControl.expectAndReturn(manager.getTransaction(), tx); + txControl.expectAndReturn(tx.isActive(), true); + tx.rollback(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) { + throw new RuntimeException("some exception"); + } + }); + } + }); + fail("Should have propagated RuntimeException"); + } + catch (RuntimeException ex) { + // expected + assertEquals("some exception", ex.getMessage()); + } + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testTransactionRollbackWithAlreadyRolledBack() { + managerControl.expectAndReturn(manager.getTransaction(), tx); + txControl.expectAndReturn(tx.isActive(), false); + // tx.rollback(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) { + throw new RuntimeException("some exception"); + } + }); + } + }); + fail("Should have propagated RuntimeException"); + } + catch (RuntimeException ex) { + // expected + } + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testTransactionRollbackOnly() { + managerControl.expectAndReturn(manager.getTransaction(), tx); + txControl.expectAndReturn(tx.isActive(), true); + manager.flush(); + tx.rollback(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + + Object res = template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) { + em.flush(); + return l; + } + }); + status.setRollbackOnly(); + + return res; + } + }); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testParticipatingTransactionWithCommit() { + managerControl.expectAndReturn(manager.getTransaction(), tx, 2); + manager.flush(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + txControl.reset(); + txControl.expectAndReturn(tx.getRollbackOnly(), false); + tx.commit(); + txControl.replay(); + + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) { + em.flush(); + return l; + } + }); + } + }); + } + }); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testParticipatingTransactionWithRollback() { + managerControl.expectAndReturn(manager.getTransaction(), tx, 2); + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + txControl.reset(); + txControl.expectAndReturn(tx.isActive(), true, 2); + tx.setRollbackOnly(); + tx.rollback(); + txControl.replay(); + + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) { + throw new RuntimeException("exception"); + } + }); + } + }); + } + }); + fail("Should have propagated RuntimeException"); + } + catch (RuntimeException ex) { + // expected + } + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testParticipatingTransactionWithRollbackOnly() { + managerControl.expectAndReturn(manager.getTransaction(), tx, 3); + manager.flush(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + txControl.reset(); + txControl.expectAndReturn(tx.isActive(), true); + tx.setRollbackOnly(); + txControl.expectAndReturn(tx.getRollbackOnly(), true); + tx.commit(); + txControl.setThrowable(new RollbackException()); + txControl.replay(); + + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + + template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em2) { + em2.flush(); + return l; + } + }); + + status.setRollbackOnly(); + return null; + } + }); + } + }); + fail("Should have thrown TransactionSystemException"); + } + catch (TransactionSystemException tse) { + // expected + assertTrue(tse.getCause() instanceof RollbackException); + } + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testParticipatingTransactionWithRequiresNew() { + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + factoryControl.expectAndReturn(factory.createEntityManager(), manager); + managerControl.expectAndReturn(manager.getTransaction(), tx, 5); + manager.flush(); + manager.close(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + txControl.verify(); + txControl.reset(); + + tx.begin(); + txControl.expectAndReturn(tx.getRollbackOnly(), false); + tx.commit(); + txControl.expectAndReturn(tx.getRollbackOnly(), false); + tx.commit(); + + txControl.replay(); + + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em2) { + em2.flush(); + return l; + } + }); + } + }); + } + }); + assertSame(l, result); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testParticipatingTransactionWithRequiresNewAndPrebound() { + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + managerControl.expectAndReturn(manager.getTransaction(), tx, 5); + manager.flush(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + TransactionSynchronizationManager.bindResource(factory, new EntityManagerHolder(manager)); + + try { + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + txControl.verify(); + txControl.reset(); + + tx.begin(); + txControl.expectAndReturn(tx.getRollbackOnly(), false); + tx.commit(); + txControl.expectAndReturn(tx.getRollbackOnly(), false); + tx.commit(); + + txControl.replay(); + + JpaTemplate template2 = new JpaTemplate(factory); + template2.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) throws PersistenceException { + return null; + } + }); + + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em2) { + em2.flush(); + return l; + } + }); + } + }); + } + }); + assertSame(l, result); + } + finally { + TransactionSynchronizationManager.unbindResource(factory); + } + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testPropagationSupportsAndRequiresNew() { + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + + manager.flush(); + managerControl.expectAndReturn(manager.getTransaction(), tx, 2); + txControl.expectAndReturn(tx.getRollbackOnly(), false); + tx.commit(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertFalse(TransactionSynchronizationManager.hasResource(factory)); + TransactionTemplate tt2 = new TransactionTemplate(transactionManager); + tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + return tt2.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em2) { + em2.flush(); + return l; + } + }); + } + }); + } + }); + assertSame(l, result); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testPropagationSupportsAndRequiresNewAndEarlyAccess() { + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + + factoryControl.expectAndReturn(factory.createEntityManager(), manager); + managerControl.expectAndReturn(manager.getTransaction(), tx, 2); + manager.flush(); + manager.close(); + txControl.expectAndReturn(tx.getRollbackOnly(), false); + tx.commit(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + JpaTemplate template2 = new JpaTemplate(factory); + template2.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) throws PersistenceException { + return null; + } + }); + + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + TransactionTemplate tt2 = new TransactionTemplate(transactionManager); + tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + return tt2.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em2) { + em2.flush(); + return l; + } + }); + } + }); + } + }); + assertSame(l, result); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testTransactionWithRequiresNewInAfterCompletion() { + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + MockControl managerControl2 = MockControl.createControl(EntityManager.class); + EntityManager manager2 = (EntityManager) managerControl2.getMock(); + MockControl txControl2 = MockControl.createControl(EntityTransaction.class); + EntityTransaction tx2 = (EntityTransaction) txControl2.getMock(); + + managerControl.expectAndReturn(manager.getTransaction(), tx, 2); + factoryControl.expectAndReturn(factory.createEntityManager(), manager2); + managerControl2.expectAndReturn(manager2.getTransaction(), tx2, 3); + txControl.expectAndReturn(tx.getRollbackOnly(), false); + txControl2.expectAndReturn(tx2.getRollbackOnly(), false); + manager.flush(); + tx.commit(); + tx2.begin(); + tx2.commit(); + manager2.flush(); + manager2.close(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + managerControl2.replay(); + txControl2.replay(); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em2) { + em2.flush(); + return null; + } + }); + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { + public void afterCompletion(int status) { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em2) { + em2.flush(); + return null; + } + }); + } + }); + } + }); + return null; + } + }); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + managerControl2.verify(); + txControl2.verify(); + } + + public void testTransactionCommitWithPropagationSupports() { + managerControl.reset(); + txControl.reset(); + + manager.flush(); + manager.close(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue(!status.isNewTransaction()); + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) { + em.flush(); + return l; + } + }); + } + }); + assertSame(l, result); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testTransactionRollbackWithPropagationSupports() { + managerControl.reset(); + txControl.reset(); + + manager.flush(); + manager.close(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue(!status.isNewTransaction()); + template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) { + em.flush(); + return null; + } + }); + status.setRollbackOnly(); + return null; + } + }); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testTransactionCommitWithPrebound() { + factoryControl.reset(); + managerControl.reset(); + txControl.reset(); + + managerControl.expectAndReturn(manager.getTransaction(), tx, 3); + tx.begin(); + txControl.expectAndReturn(tx.getRollbackOnly(), false); + tx.commit(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.bindResource(factory, new EntityManagerHolder(manager)); + + try { + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) { + return l; + } + }); + } + }); + assertSame(l, result); + + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + } + finally { + TransactionSynchronizationManager.unbindResource(factory); + } + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testTransactionRollbackWithPrebound() { + factoryControl.reset(); + managerControl.reset(); + txControl.reset(); + + managerControl.expectAndReturn(manager.getTransaction(), tx, 2); + tx.begin(); + txControl.expectAndReturn(tx.isActive(), true); + tx.rollback(); + manager.clear(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.bindResource(factory, new EntityManagerHolder(manager)); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) { + return null; + } + }); + status.setRollbackOnly(); + return null; + } + }); + + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + } + finally { + TransactionSynchronizationManager.unbindResource(factory); + } + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testTransactionCommitWithPreboundAndPropagationSupports() { + factoryControl.reset(); + managerControl.reset(); + txControl.reset(); + + manager.joinTransaction(); + manager.flush(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.bindResource(factory, new EntityManagerHolder(manager)); + + try { + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue(!status.isNewTransaction()); + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) { + em.flush(); + return l; + } + }); + } + }); + assertSame(l, result); + + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + } + finally { + TransactionSynchronizationManager.unbindResource(factory); + } + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testTransactionRollbackWithPreboundAndPropagationSupports() { + factoryControl.reset(); + managerControl.reset(); + txControl.reset(); + + manager.joinTransaction(); + manager.flush(); + manager.clear(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.bindResource(factory, new EntityManagerHolder(manager)); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue(!status.isNewTransaction()); + template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) { + em.flush(); + return null; + } + }); + status.setRollbackOnly(); + return null; + } + }); + + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + } + finally { + TransactionSynchronizationManager.unbindResource(factory); + } + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + + public void testTransactionCommitWithDataSource() throws SQLException { + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + transactionManager.setDataSource(ds); + + managerControl.expectAndReturn(manager.getTransaction(), tx); + managerControl.expectAndReturn(manager.getTransaction(), tx); + txControl.expectAndReturn(tx.getRollbackOnly(), false); + tx.commit(); + manager.flush(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + dsControl.replay(); + + final List l = new ArrayList(); + l.add("test"); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + return template.execute(new JpaCallback() { + public Object doInJpa(EntityManager em) { + em.flush(); + return l; + } + }); + } + }); + + assertTrue(result == l); + + assertTrue(!TransactionSynchronizationManager.hasResource(factory)); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + dsControl.verify(); + } + + public void testInvalidIsolation() { + tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); + txControl.reset(); + managerControl.reset(); + + manager.close(); + + factoryControl.replay(); + managerControl.replay(); + txControl.replay(); + + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + } + }); + fail("Should have thrown InvalidIsolationLevelException"); + } + catch (InvalidIsolationLevelException ex) { + // expected + } + + factoryControl.verify(); + managerControl.verify(); + txControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBeanTests.java new file mode 100644 index 00000000000..dbafff74ab1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBeanTests.java @@ -0,0 +1,397 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa; + +import java.util.Map; +import java.util.Properties; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityTransaction; +import javax.persistence.OptimisticLockException; +import javax.persistence.PersistenceException; +import javax.persistence.spi.PersistenceProvider; +import javax.persistence.spi.PersistenceUnitInfo; +import javax.persistence.spi.PersistenceUnitTransactionType; + +import org.easymock.MockControl; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver; +import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.interceptor.DefaultTransactionAttribute; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class LocalContainerEntityManagerFactoryBeanTests extends AbstractEntityManagerFactoryBeanTests { + + // Static fields set by inner class DummyPersistenceProvider + + private static Map actualProps; + + private static PersistenceUnitInfo actualPui; + + + public void testValidPersistenceUnit() throws Exception { + parseValidPersistenceUnit(); + } + + public void testExceptionTranslationWithNoDialect() throws Exception { + LocalContainerEntityManagerFactoryBean cefb = parseValidPersistenceUnit(); + EntityManagerFactory emf = cefb.getObject(); + assertNull("No dialect set", cefb.getJpaDialect()); + + RuntimeException in1 = new RuntimeException("in1"); + PersistenceException in2 = new PersistenceException(); + assertNull("No translation here", cefb.translateExceptionIfPossible(in1)); + DataAccessException dex = cefb.translateExceptionIfPossible(in2); + assertNotNull(dex); + assertSame(in2, dex.getCause()); + } + + public void testEntityManagerFactoryIsProxied() throws Exception { + LocalContainerEntityManagerFactoryBean cefb = parseValidPersistenceUnit(); + EntityManagerFactory emf = cefb.getObject(); + assertSame("EntityManagerFactory reference must be cached after init", emf, cefb.getObject()); + + assertNotSame("EMF must be proxied", mockEmf, emf); + assertTrue(emf.equals(emf)); + } + + public void testApplicationManagedEntityManagerWithoutTransaction() throws Exception { + Object testEntity = new Object(); + + MockControl emMc = MockControl.createControl(EntityManager.class); + EntityManager mockEm = (EntityManager) emMc.getMock(); + mockEm.contains(testEntity); + emMc.setReturnValue(false); + emMc.replay(); + + // finish recording mock calls + mockEmf.createEntityManager(); + emfMc.setReturnValue(mockEm); + mockEmf.close(); + emfMc.setVoidCallable(); + emfMc.replay(); + + LocalContainerEntityManagerFactoryBean cefb = parseValidPersistenceUnit(); + EntityManagerFactory emf = cefb.getObject(); + assertSame("EntityManagerFactory reference must be cached after init", emf, cefb.getObject()); + + assertNotSame("EMF must be proxied", mockEmf, emf); + EntityManager em = emf.createEntityManager(); + assertFalse(em.contains(testEntity)); + + cefb.destroy(); + + emfMc.verify(); + emMc.verify(); + } + + public void testApplicationManagedEntityManagerWithTransaction() throws Exception { + Object testEntity = new Object(); + + MockControl tmMc = MockControl.createControl(EntityTransaction.class); + EntityTransaction mockTx = (EntityTransaction) tmMc.getMock(); + mockTx.isActive(); + tmMc.setReturnValue(false); + mockTx.begin(); + tmMc.setVoidCallable(); + mockTx.commit(); + tmMc.setVoidCallable(); + tmMc.replay(); + + // This one's for the tx (shared) + MockControl sharedEmMc = MockControl.createControl(EntityManager.class); + EntityManager sharedEm = (EntityManager) sharedEmMc.getMock(); + sharedEm.getTransaction(); + sharedEmMc.setReturnValue(new NoOpEntityTransaction(), 3); + sharedEm.close(); + sharedEmMc.setVoidCallable(); + sharedEmMc.replay(); + mockEmf.createEntityManager(); + emfMc.setReturnValue(sharedEm); + + // This is the application-specific one + MockControl emMc = MockControl.createControl(EntityManager.class); + EntityManager mockEm = (EntityManager) emMc.getMock(); + mockEm.getTransaction(); + emMc.setReturnValue(mockTx, 3); + mockEm.contains(testEntity); + emMc.setReturnValue(false); + emMc.replay(); + + mockEmf.createEntityManager(); + emfMc.setReturnValue(mockEm); + mockEmf.close(); + emfMc.setVoidCallable(); + emfMc.replay(); + + LocalContainerEntityManagerFactoryBean cefb = parseValidPersistenceUnit(); + + JpaTransactionManager jpatm = new JpaTransactionManager(); + jpatm.setEntityManagerFactory(cefb.getObject()); + + TransactionStatus txStatus = jpatm.getTransaction(new DefaultTransactionAttribute()); + + EntityManagerFactory emf = cefb.getObject(); + assertSame("EntityManagerFactory reference must be cached after init", emf, cefb.getObject()); + + assertNotSame("EMF must be proxied", mockEmf, emf); + EntityManager em = emf.createEntityManager(); + em.joinTransaction(); + assertFalse(em.contains(testEntity)); + + jpatm.commit(txStatus); + + cefb.destroy(); + + emfMc.verify(); + emMc.verify(); + tmMc.verify(); + } + + public void testApplicationManagedEntityManagerWithTransactionAndCommitException() throws Exception { + Object testEntity = new Object(); + + MockControl tmMc = MockControl.createControl(EntityTransaction.class); + EntityTransaction mockTx = (EntityTransaction) tmMc.getMock(); + mockTx.isActive(); + tmMc.setReturnValue(false); + mockTx.begin(); + tmMc.setVoidCallable(); + mockTx.commit(); + tmMc.setThrowable(new OptimisticLockException()); + tmMc.replay(); + + // This one's for the tx (shared) + MockControl sharedEmMc = MockControl.createControl(EntityManager.class); + EntityManager sharedEm = (EntityManager) sharedEmMc.getMock(); + sharedEm.getTransaction(); + sharedEmMc.setReturnValue(new NoOpEntityTransaction(), 3); + sharedEm.close(); + sharedEmMc.setVoidCallable(); + sharedEmMc.replay(); + mockEmf.createEntityManager(); + emfMc.setReturnValue(sharedEm); + + // This is the application-specific one + MockControl emMc = MockControl.createControl(EntityManager.class); + EntityManager mockEm = (EntityManager) emMc.getMock(); + mockEm.getTransaction(); + emMc.setReturnValue(mockTx, 3); + mockEm.contains(testEntity); + emMc.setReturnValue(false); + emMc.replay(); + + mockEmf.createEntityManager(); + emfMc.setReturnValue(mockEm); + mockEmf.close(); + emfMc.setVoidCallable(); + emfMc.replay(); + + LocalContainerEntityManagerFactoryBean cefb = parseValidPersistenceUnit(); + + JpaTransactionManager jpatm = new JpaTransactionManager(); + jpatm.setEntityManagerFactory(cefb.getObject()); + + TransactionStatus txStatus = jpatm.getTransaction(new DefaultTransactionAttribute()); + + EntityManagerFactory emf = cefb.getObject(); + assertSame("EntityManagerFactory reference must be cached after init", emf, cefb.getObject()); + + assertNotSame("EMF must be proxied", mockEmf, emf); + EntityManager em = emf.createEntityManager(); + em.joinTransaction(); + assertFalse(em.contains(testEntity)); + + try { + jpatm.commit(txStatus); + fail("Should have thrown OptimisticLockingFailureException"); + } + catch (OptimisticLockingFailureException ex) { + // expected + } + + cefb.destroy(); + + emfMc.verify(); + emMc.verify(); + tmMc.verify(); + } + + public void testApplicationManagedEntityManagerWithJtaTransaction() throws Exception { + Object testEntity = new Object(); + + // This one's for the tx (shared) + MockControl sharedEmMc = MockControl.createControl(EntityManager.class); + EntityManager sharedEm = (EntityManager) sharedEmMc.getMock(); + sharedEm.getTransaction(); + sharedEmMc.setReturnValue(new NoOpEntityTransaction(), 3); + sharedEm.close(); + sharedEmMc.setVoidCallable(1); + sharedEmMc.replay(); + mockEmf.createEntityManager(); + emfMc.setReturnValue(sharedEm); + + // This is the application-specific one + MockControl emMc = MockControl.createControl(EntityManager.class); + EntityManager mockEm = (EntityManager) emMc.getMock(); + mockEm.joinTransaction(); + emMc.setVoidCallable(1); + mockEm.contains(testEntity); + emMc.setReturnValue(false); + emMc.replay(); + + mockEmf.createEntityManager(); + emfMc.setReturnValue(mockEm); + mockEmf.close(); + emfMc.setVoidCallable(); + emfMc.replay(); + + LocalContainerEntityManagerFactoryBean cefb = parseValidPersistenceUnit(); + MutablePersistenceUnitInfo pui = ((MutablePersistenceUnitInfo) cefb.getPersistenceUnitInfo()); + pui.setTransactionType(PersistenceUnitTransactionType.JTA); + + JpaTransactionManager jpatm = new JpaTransactionManager(); + jpatm.setEntityManagerFactory(cefb.getObject()); + + TransactionStatus txStatus = jpatm.getTransaction(new DefaultTransactionAttribute()); + + EntityManagerFactory emf = cefb.getObject(); + assertSame("EntityManagerFactory reference must be cached after init", emf, cefb.getObject()); + + assertNotSame("EMF must be proxied", mockEmf, emf); + EntityManager em = emf.createEntityManager(); + em.joinTransaction(); + assertFalse(em.contains(testEntity)); + + jpatm.commit(txStatus); + + cefb.destroy(); + + emfMc.verify(); + emMc.verify(); + } + + public LocalContainerEntityManagerFactoryBean parseValidPersistenceUnit() throws Exception { + LocalContainerEntityManagerFactoryBean emfb = createEntityManagerFactoryBean( + "org/springframework/orm/jpa/domain/persistence.xml", null, + "Person"); + return emfb; + } + + public void testInvalidPersistenceUnitName() throws Exception { + try { + createEntityManagerFactoryBean("org/springframework/orm/jpa/domain/persistence.xml", null, "call me Bob"); + fail("Should not create factory with this name"); + } + catch (IllegalArgumentException ex) { + // Ok + } + } + + protected LocalContainerEntityManagerFactoryBean createEntityManagerFactoryBean( + String persistenceXml, Properties props, String entityManagerName) throws Exception { + + // This will be set by DummyPersistenceProvider + actualPui = null; + actualProps = null; + + LocalContainerEntityManagerFactoryBean containerEmfb = new LocalContainerEntityManagerFactoryBean(); + + containerEmfb.setPersistenceUnitName(entityManagerName); + containerEmfb.setPersistenceProviderClass(DummyContainerPersistenceProvider.class); + if (props != null) { + containerEmfb.setJpaProperties(props); + } + containerEmfb.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver()); + containerEmfb.setPersistenceXmlLocation(persistenceXml); + containerEmfb.afterPropertiesSet(); + + assertEquals(entityManagerName, actualPui.getPersistenceUnitName()); + if (props != null) { + assertEquals(props, actualProps); + } + //checkInvariants(containerEmfb); + + return containerEmfb; + + //containerEmfb.destroy(); + //emfMc.verify(); + } + + public void testRejectsMissingPersistenceUnitInfo() throws Exception { + LocalContainerEntityManagerFactoryBean containerEmfb = new LocalContainerEntityManagerFactoryBean(); + String entityManagerName = "call me Bob"; + + containerEmfb.setPersistenceUnitName(entityManagerName); + containerEmfb.setPersistenceProviderClass(DummyContainerPersistenceProvider.class); + + try { + containerEmfb.afterPropertiesSet(); + fail(); + } + catch (IllegalArgumentException ex) { + // Ok + } + } + + + private static class DummyContainerPersistenceProvider implements PersistenceProvider { + + public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo pui, Map map) { + actualPui = pui; + actualProps = map; + return mockEmf; + } + + public EntityManagerFactory createEntityManagerFactory(String emfName, Map properties) { + throw new UnsupportedOperationException(); + } + } + + + private static class NoOpEntityTransaction implements EntityTransaction { + + public void begin() { + } + + public void commit() { + } + + public void rollback() { + } + + public void setRollbackOnly() { + throw new UnsupportedOperationException(); + } + + public boolean getRollbackOnly() { + return false; + } + + public boolean isActive() { + return false; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBeanTests.java new file mode 100644 index 00000000000..b2d3557e9b8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBeanTests.java @@ -0,0 +1,94 @@ +/* + * Copyright 2002-2006 the original author 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.orm.jpa; + +import java.util.Map; +import java.util.Properties; + +import javax.persistence.EntityManagerFactory; +import javax.persistence.spi.PersistenceProvider; +import javax.persistence.spi.PersistenceUnitInfo; + +/** + * @author Rod Johnson + */ +public class LocalEntityManagerFactoryBeanTests extends AbstractEntityManagerFactoryBeanTests { + + // Static fields set by inner class DummyPersistenceProvider + + private static String actualName; + + private static Map actualProps; + + + @Override + protected void setUp() throws Exception { + super.setUp(); + mockEmf.close(); + emfMc.setVoidCallable(); + emfMc.replay(); + } + + public void testValidUsageWithDefaultProperties() throws Exception { + testValidUsage(null); + } + + public void testValidUsageWithExplicitProperties() throws Exception { + testValidUsage(new Properties()); + } + + protected void testValidUsage(Properties props) throws Exception { + // This will be set by DummyPersistenceProvider + actualName = null; + actualProps = null; + + LocalEntityManagerFactoryBean lemfb = new LocalEntityManagerFactoryBean(); + String entityManagerName = "call me Bob"; + + lemfb.setPersistenceUnitName(entityManagerName); + lemfb.setPersistenceProviderClass(DummyPersistenceProvider.class); + if (props != null) { + lemfb.setJpaProperties(props); + } + lemfb.afterPropertiesSet(); + + assertSame(entityManagerName, actualName); + if (props != null) { + assertEquals(props, actualProps); + } + checkInvariants(lemfb); + + lemfb.destroy(); + + emfMc.verify(); + } + + + protected static class DummyPersistenceProvider implements PersistenceProvider { + + public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo pui, Map map) { + throw new UnsupportedOperationException(); + } + + public EntityManagerFactory createEntityManagerFactory(String emfName, Map properties) { + actualName = emfName; + actualProps = properties; + return mockEmf; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/META-INF/persistence.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/META-INF/persistence.xml new file mode 100644 index 00000000000..0e7290ef8f6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/META-INF/persistence.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/ContextualPerson.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/ContextualPerson.java new file mode 100644 index 00000000000..9bc00960fe0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/ContextualPerson.java @@ -0,0 +1,105 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa.domain; + +import javax.persistence.Basic; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.EntityManager; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; +import javax.persistence.PersistenceContext; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.annotation.Configurable; + +/** + * @author Juergen Hoeller + */ +@Entity +@Configurable +public class ContextualPerson { + + @Id + @GeneratedValue(strategy=GenerationType.AUTO) + private Integer id; + + private transient TestBean testBean; + + // Lazy relationship to force use of instrumentation in JPA implementation. + // TopLink, at least, will not instrument classes unless absolutely necessary. + @OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST) + @JoinColumn(name="DRIVERS_LICENSE_ID") + private DriversLicense driversLicense; + + private String first_name; + + @Basic(fetch=FetchType.LAZY) + private String last_name; + + @PersistenceContext + public transient EntityManager entityManager; + + + public Integer getId() { + return id; + } + + public void setTestBean(TestBean testBean) { + this.testBean = testBean; + } + + public TestBean getTestBean() { + return testBean; + } + + public void setFirstName(String firstName) { + this.first_name = firstName; + } + + public String getFirstName() { + return this.first_name; + } + + public void setLastName(String lastName) { + this.last_name = lastName; + } + + public String getLastName() { + return this.last_name; + } + + public void setDriversLicense(DriversLicense driversLicense) { + this.driversLicense = driversLicense; + } + + public DriversLicense getDriversLicense() { + return this.driversLicense; + } + + + @Override + public String toString() { + return getClass().getName() + ":(" + hashCode() + ") id=" + id + + "; firstName=" + first_name + "; lastName=" + last_name + "; testBean=" + testBean; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/DriversLicense.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/DriversLicense.java new file mode 100644 index 00000000000..c0b90036547 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/DriversLicense.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2006 the original author 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.orm.jpa.domain; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name="DRIVERS_LICENSE") +public class DriversLicense { + + @Id + private int id; + + private String serial_number; + + + protected DriversLicense() { + } + + public DriversLicense(String serialNumber) { + this.serial_number = serialNumber; + } + + public String getSerialNumber() { + return serial_number; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/Person.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/Person.java new file mode 100644 index 00000000000..69c51ca869f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/Person.java @@ -0,0 +1,103 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa.domain; + +import javax.persistence.Basic; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.annotation.Configurable; + +/** + * Simple JavaBean domain object representing an person. + * + * @author Rod Johnson + */ +@Entity +@Configurable +public class Person { + + @Id + @GeneratedValue(strategy=GenerationType.AUTO) + private Integer id; + + private transient TestBean testBean; + + // Lazy relationship to force use of instrumentation in JPA implementation. + // TopLink, at least, will not instrument classes unless absolutely necessary. + @OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST) + @JoinColumn(name="DRIVERS_LICENSE_ID") + private DriversLicense driversLicense; + + private String first_name; + + @Basic(fetch=FetchType.LAZY) + private String last_name; + + + public Integer getId() { + return id; + } + + public void setTestBean(TestBean testBean) { + this.testBean = testBean; + } + + public TestBean getTestBean() { + return testBean; + } + + public void setFirstName(String firstName) { + this.first_name = firstName; + } + + public String getFirstName() { + return this.first_name; + } + + public void setLastName(String lastName) { + this.last_name = lastName; + } + + public String getLastName() { + return this.last_name; + } + + public void setDriversLicense(DriversLicense driversLicense) { + this.driversLicense = driversLicense; + } + + public DriversLicense getDriversLicense() { + return this.driversLicense; + } + + + @Override + public String toString() { + return getClass().getName() + ":(" + hashCode() + ") id=" + id + + "; firstName=" + first_name + "; lastName=" + last_name + "; testBean=" + testBean; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/persistence-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/persistence-context.xml new file mode 100644 index 00000000000..b161b07f79e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/persistence-context.xml @@ -0,0 +1,13 @@ + + + + org.springframework.orm.jpa.domain.ContextualPerson + org.springframework.orm.jpa.domain.DriversLicense + org.springframework.orm.jpa.domain.Person + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/persistence-multi.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/persistence-multi.xml new file mode 100644 index 00000000000..217e8537ff5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/persistence-multi.xml @@ -0,0 +1,17 @@ + + + + org.springframework.orm.jpa.domain.Person + org.springframework.orm.jpa.domain.DriversLicense + + + + + org.springframework.beans.TestBean + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/persistence.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/persistence.xml new file mode 100644 index 00000000000..c75da3e4a58 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/domain/persistence.xml @@ -0,0 +1,12 @@ + + + + org.springframework.orm.jpa.domain.Person + org.springframework.orm.jpa.domain.DriversLicense + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/eclipselink/EclipseLinkEntityManagerFactoryIntegrationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/eclipselink/EclipseLinkEntityManagerFactoryIntegrationTests.java new file mode 100644 index 00000000000..4e092f7ffc3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/eclipselink/EclipseLinkEntityManagerFactoryIntegrationTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa.eclipselink; + +import org.eclipse.persistence.jpa.JpaEntityManager; + +import org.springframework.orm.jpa.AbstractContainerEntityManagerFactoryIntegrationTests; +import org.springframework.orm.jpa.EntityManagerFactoryInfo; + +/** + * EclipseLink-specific JPA tests. + * + * @author Juergen Hoeller + */ +public class EclipseLinkEntityManagerFactoryIntegrationTests extends AbstractContainerEntityManagerFactoryIntegrationTests { + + protected String[] getConfigLocations() { + return ECLIPSELINK_CONFIG_LOCATIONS; + } + + + public void testCanCastNativeEntityManagerFactoryToTopLinkEntityManagerFactoryImpl() { + EntityManagerFactoryInfo emfi = (EntityManagerFactoryInfo) entityManagerFactory; + assertTrue(emfi.getNativeEntityManagerFactory().getClass().getName().endsWith("EntityManagerFactoryImpl")); + } + + public void testCanCastSharedEntityManagerProxyToTopLinkEntityManager() { + assertTrue(sharedEntityManager instanceof JpaEntityManager); + JpaEntityManager eclipselinkEntityManager = (JpaEntityManager) sharedEntityManager; + assertNotNull(eclipselinkEntityManager.getActiveSession()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/eclipselink/eclipselink-manager.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/eclipselink/eclipselink-manager.xml new file mode 100644 index 00000000000..625605e8278 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/eclipselink/eclipselink-manager.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java new file mode 100644 index 00000000000..d8acb689db4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java @@ -0,0 +1,80 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa.hibernate; + +import java.util.List; + +import org.hibernate.Query; +import org.hibernate.SessionFactory; +import org.hibernate.ejb.HibernateEntityManager; +import org.hibernate.ejb.HibernateEntityManagerFactory; + +import org.springframework.orm.jpa.AbstractContainerEntityManagerFactoryIntegrationTests; +import org.springframework.orm.jpa.EntityManagerFactoryInfo; +import org.springframework.orm.jpa.domain.Person; + +/** + * Hibernate-specific JPA tests. + * + * @author Juergen Hoeller + * @author Rod Johnson + */ +public class HibernateEntityManagerFactoryIntegrationTests extends + AbstractContainerEntityManagerFactoryIntegrationTests { + + private SessionFactory sessionFactory; + + + public void setSessionFactory(SessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + } + + protected String[] getConfigLocations() { + return HIBERNATE_CONFIG_LOCATIONS; + } + + + public void testCanCastNativeEntityManagerFactoryToHibernateEntityManagerFactoryImpl() { + EntityManagerFactoryInfo emfi = (EntityManagerFactoryInfo) entityManagerFactory; + assertTrue(emfi.getNativeEntityManagerFactory() instanceof HibernateEntityManagerFactory); + } + + public void testCanCastSharedEntityManagerProxyToHibernateEntityManager() { + assertTrue(sharedEntityManager instanceof HibernateEntityManager); + HibernateEntityManager hibernateEntityManager = (HibernateEntityManager) sharedEntityManager; + assertNotNull(hibernateEntityManager.getSession()); + } + + public void testWithHibernateSessionFactory() { + // Add with JDBC + String firstName = "Tony"; + insertPerson(firstName); + + Query q = this.sessionFactory.getCurrentSession().createQuery("select p from Person as p"); + List people = q.list(); + + assertEquals(1, people.size()); + assertEquals(firstName, people.get(0).getFirstName()); + } + + public void testConfigurablePerson() { + Query q = this.sessionFactory.getCurrentSession().createQuery("select p from ContextualPerson as p"); + assertEquals(0, q.list().size()); + //assertNotNull(new ContextualPerson().entityManager); TODO + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/HibernateMultiEntityManagerFactoryIntegrationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/HibernateMultiEntityManagerFactoryIntegrationTests.java new file mode 100644 index 00000000000..bcff4922b82 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/HibernateMultiEntityManagerFactoryIntegrationTests.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2006 the original author 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.orm.jpa.hibernate; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; + +import org.springframework.orm.jpa.AbstractContainerEntityManagerFactoryIntegrationTests; + +/** + * Hibernate-specific JPA tests with multiple EntityManagerFactory instances. + * + * @author Juergen Hoeller + */ +public class HibernateMultiEntityManagerFactoryIntegrationTests extends + AbstractContainerEntityManagerFactoryIntegrationTests { + + private EntityManagerFactory entityManagerFactory2; + + + public HibernateMultiEntityManagerFactoryIntegrationTests() { + setAutowireMode(AUTOWIRE_BY_NAME); + } + + public void setEntityManagerFactory2(EntityManagerFactory entityManagerFactory2) { + this.entityManagerFactory2 = entityManagerFactory2; + } + + protected String[] getConfigLocations() { + return new String[] { + "/org/springframework/orm/jpa/hibernate/hibernate-manager-multi.xml", + "/org/springframework/orm/jpa/memdb.xml", + }; + } + + + public void testEntityManagerFactory2() { + EntityManager em = this.entityManagerFactory2.createEntityManager(); + try { + em.createQuery("select tb from TestBean"); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + finally { + em.close(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/hibernate-manager-multi.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/hibernate-manager-multi.xml new file mode 100644 index 00000000000..3ce1da843c6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/hibernate-manager-multi.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + org.hibernate.cache.HashtableCacheProvider + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/hibernate-manager.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/hibernate-manager.xml new file mode 100644 index 00000000000..6779b221c3b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/hibernate/hibernate-manager.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + org.hibernate.cache.HashtableCacheProvider + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/inject.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/inject.xml new file mode 100644 index 00000000000..09aa0eb7f31 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/inject.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/jpa-archive.jar b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/jpa-archive.jar new file mode 100644 index 0000000000000000000000000000000000000000..8e507d7e96e4d237310653ef39cd1877c6c4ba6e GIT binary patch literal 403 zcmWIWW@Zs#U}9ik*j)VB1W3UFCy?dq8sezy>F1^&09D4p@N4xZlfYe^Y^#CNo{S6( zBFM@LQj3Z+i%aw>a&vn74EdT3cwC<=6}D?wduEuk%wf2)(A!+3l_SWM?V*E39dnSN z@-+6>zwPUvFP?W{!Q}-ek#EH}EZAF|eC(&Y-lT^-KD^V~McJRIoA)lh&6lD*i}}+% z2d$D}gi%FgzI;00}yDVgLXD literal 0 HcmV?d00001 diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/memdb.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/memdb.xml new file mode 100644 index 00000000000..4b441515cb0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/memdb.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/multi-jpa-emf.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/multi-jpa-emf.xml new file mode 100644 index 00000000000..74226ccb882 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/multi-jpa-emf.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/OpenJpaEntityManagerFactoryIntegrationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/OpenJpaEntityManagerFactoryIntegrationTests.java new file mode 100644 index 00000000000..fbdb0eda301 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/OpenJpaEntityManagerFactoryIntegrationTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2002-2006 the original author 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.orm.jpa.openjpa; + +import java.util.List; + +import javax.persistence.FlushModeType; +import javax.persistence.Query; + +import org.apache.openjpa.persistence.OpenJPAEntityManager; +import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory; + +import org.springframework.orm.jpa.AbstractContainerEntityManagerFactoryIntegrationTests; +import org.springframework.orm.jpa.EntityManagerFactoryInfo; +import org.springframework.orm.jpa.SharedEntityManagerCreator; +import org.springframework.orm.jpa.domain.Person; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * OpenJPA-specific JPA tests. + * + * @author Costin Leau + */ +public class OpenJpaEntityManagerFactoryIntegrationTests extends AbstractContainerEntityManagerFactoryIntegrationTests { + + protected String[] getConfigLocations() { + return OPENJPA_CONFIG_LOCATIONS; + } + + public void testCanCastNativeEntityManagerFactoryToOpenJpaEntityManagerFactoryImpl() { + EntityManagerFactoryInfo emfi = (EntityManagerFactoryInfo) entityManagerFactory; + assertTrue("native EMF expected", emfi.getNativeEntityManagerFactory() instanceof OpenJPAEntityManagerFactory); + } + + public void testCanCastSharedEntityManagerProxyToOpenJpaEntityManager() { + assertTrue("native EM expected", sharedEntityManager instanceof OpenJPAEntityManager); + } + + public void testCanGetSharedOpenJpaEntityManagerProxy() { + OpenJPAEntityManager openJPAEntityManager = (OpenJPAEntityManager) SharedEntityManagerCreator.createSharedEntityManager( + entityManagerFactory, null, OpenJPAEntityManager.class); + assertNotNull(openJPAEntityManager.getDelegate()); + } + + public void testSavepoint() { + TransactionTemplate tt = new TransactionTemplate(transactionManager); + tt.setPropagationBehavior(TransactionTemplate.PROPAGATION_NESTED); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + Person tony = new Person(); + tony.setFirstName("Tony"); + sharedEntityManager.merge(tony); + Query q = sharedEntityManager.createQuery("select p from Person as p"); + q.setFlushMode(FlushModeType.COMMIT); + List people = q.getResultList(); + assertEquals(1, people.size()); + assertEquals("Tony", people.get(0).getFirstName()); + status.setRollbackOnly(); + } + }); + Query q = sharedEntityManager.createQuery("select p from Person as p"); + List people = q.getResultList(); + assertEquals(0, people.size()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/OpenJpaEntityManagerFactoryWithAspectJWeavingIntegrationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/OpenJpaEntityManagerFactoryWithAspectJWeavingIntegrationTests.java new file mode 100644 index 00000000000..fdcc61d997f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/OpenJpaEntityManagerFactoryWithAspectJWeavingIntegrationTests.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa.openjpa; + +/** + * Test that AspectJ weaving (in particular the currently shipped aspects) work with JPA (see SPR-3873 for more details). + * + * @author Ramnivas Laddad + */ +public class OpenJpaEntityManagerFactoryWithAspectJWeavingIntegrationTests extends OpenJpaEntityManagerFactoryIntegrationTests { + + protected String[] getConfigLocations() { + return new String[] { + "/org/springframework/orm/jpa/openjpa/openjpa-manager-aspectj-weaving.xml", + "/org/springframework/orm/jpa/memdb.xml", + "/org/springframework/orm/jpa/inject.xml"}; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/openjpa-manager-aspectj-weaving.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/openjpa-manager-aspectj-weaving.xml new file mode 100644 index 00000000000..20206d0a57b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/openjpa-manager-aspectj-weaving.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/openjpa-manager.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/openjpa-manager.xml new file mode 100644 index 00000000000..2db5444076f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/openjpa/openjpa-manager.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-complex.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-complex.xml new file mode 100644 index 00000000000..20ace4575af --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-complex.xml @@ -0,0 +1,30 @@ + + + + + This unit manages inventory for auto parts. It depends on + features provided by the com.acme.persistence + implementation. + + com.acme.AcmePersistence + jdbc/MyPartDB + ormap2.xml + order.jar + + + + + + + + com.acme.AcmePersistence + jdbc/MyDB + order2.xml + order-*.jar + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example1.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example1.xml new file mode 100644 index 00000000000..60381ff19a5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example1.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example2.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example2.xml new file mode 100644 index 00000000000..dbcaf71863a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example2.xml @@ -0,0 +1,10 @@ + + + + mappings.xml + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example3.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example3.xml new file mode 100644 index 00000000000..16afc29ec1e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example3.xml @@ -0,0 +1,11 @@ + + + + order.jar + order-supplemental.jar + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example4.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example4.xml new file mode 100644 index 00000000000..014c67d0fba --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example4.xml @@ -0,0 +1,18 @@ + + + + jdbc/MyDB + order-mappings.xml + + com.acme.Order + com.acme.Customer + com.acme.Item + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example5.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example5.xml new file mode 100644 index 00000000000..a1f2bd59b18 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example5.xml @@ -0,0 +1,14 @@ + + + + com.acme.AcmePersistence + order1.xml + order2.xml + order.jar + order-supplemental.jar + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example6.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example6.xml new file mode 100644 index 00000000000..d43117327a3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-example6.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-invalid.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-invalid.xml new file mode 100644 index 00000000000..b31889b173b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-invalid.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-no-schema.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-no-schema.xml new file mode 100644 index 00000000000..8feef91a425 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistence-no-schema.xml @@ -0,0 +1,3 @@ + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceXmlParsingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceXmlParsingTests.java new file mode 100644 index 00000000000..f33afc3cba2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceXmlParsingTests.java @@ -0,0 +1,267 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa.persistenceunit; + +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.persistence.spi.PersistenceUnitInfo; +import javax.persistence.spi.PersistenceUnitTransactionType; +import javax.sql.DataSource; + +import junit.framework.TestCase; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.UrlResource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; +import org.springframework.jdbc.datasource.lookup.MapDataSourceLookup; +import org.springframework.mock.jndi.SimpleNamingContextBuilder; + +/** + * Unit and integration tests for the JPA XML resource parsing support. + * + * @author Costin Leau + */ +public class PersistenceXmlParsingTests extends TestCase { + + public void testExample1() throws Exception { + PersistenceUnitReader reader = new PersistenceUnitReader( + new PathMatchingResourcePatternResolver(), new JndiDataSourceLookup()); + String resource = "/org/springframework/orm/jpa/persistence-example1.xml"; + PersistenceUnitInfo[] info = reader.readPersistenceUnitInfos(resource); + + assertNotNull(info); + assertEquals(1, info.length); + assertEquals("OrderManagement", info[0].getPersistenceUnitName()); + } + + public void testExample2() throws Exception { + PersistenceUnitReader reader = new PersistenceUnitReader( + new PathMatchingResourcePatternResolver(), new JndiDataSourceLookup()); + String resource = "/org/springframework/orm/jpa/persistence-example2.xml"; + PersistenceUnitInfo[] info = reader.readPersistenceUnitInfos(resource); + + assertNotNull(info); + assertEquals(1, info.length); + + assertEquals("OrderManagement2", info[0].getPersistenceUnitName()); + + assertEquals(1, info[0].getMappingFileNames().size()); + assertEquals("mappings.xml", info[0].getMappingFileNames().get(0)); + assertEquals(0, info[0].getProperties().keySet().size()); + } + + public void testExample3() throws Exception { + PersistenceUnitReader reader = new PersistenceUnitReader( + new PathMatchingResourcePatternResolver(), new JndiDataSourceLookup()); + String resource = "/org/springframework/orm/jpa/persistence-example3.xml"; + PersistenceUnitInfo[] info = reader.readPersistenceUnitInfos(resource); + + assertNotNull(info); + assertEquals(1, info.length); + assertEquals("OrderManagement3", info[0].getPersistenceUnitName()); + + assertEquals(2, info[0].getJarFileUrls().size()); + assertEquals(new ClassPathResource("order.jar").getURL(), info[0].getJarFileUrls().get(0)); + assertEquals(new ClassPathResource("order-supplemental.jar").getURL(), info[0].getJarFileUrls().get(1)); + assertEquals(0, info[0].getProperties().keySet().size()); + assertNull(info[0].getJtaDataSource()); + assertNull(info[0].getNonJtaDataSource()); + } + + public void testExample4() throws Exception { + SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder(); + DataSource ds = new DriverManagerDataSource(); + builder.bind("java:comp/env/jdbc/MyDB", ds); + + PersistenceUnitReader reader = new PersistenceUnitReader( + new PathMatchingResourcePatternResolver(), new JndiDataSourceLookup()); + String resource = "/org/springframework/orm/jpa/persistence-example4.xml"; + PersistenceUnitInfo[] info = reader.readPersistenceUnitInfos(resource); + + assertNotNull(info); + assertEquals(1, info.length); + assertEquals("OrderManagement4", info[0].getPersistenceUnitName()); + + assertEquals(1, info[0].getMappingFileNames().size()); + assertEquals("order-mappings.xml", info[0].getMappingFileNames().get(0)); + + assertEquals(3, info[0].getManagedClassNames().size()); + assertEquals("com.acme.Order", info[0].getManagedClassNames().get(0)); + assertEquals("com.acme.Customer", info[0].getManagedClassNames().get(1)); + assertEquals("com.acme.Item", info[0].getManagedClassNames().get(2)); + + assertTrue(info[0].excludeUnlistedClasses()); + + assertSame(PersistenceUnitTransactionType.RESOURCE_LOCAL, info[0].getTransactionType()); + assertEquals(0, info[0].getProperties().keySet().size()); + + // TODO this is undefined as yet. Do we look up Spring datasource? + // assertNotNull(info[0].getNonJtaDataSource()); + // + // assertEquals(ds .toString(), + // info[0].getNonJtaDataSource().toString()); + + builder.clear(); + } + + public void testExample5() throws Exception { + PersistenceUnitReader reader = new PersistenceUnitReader( + new PathMatchingResourcePatternResolver(), new JndiDataSourceLookup()); + String resource = "/org/springframework/orm/jpa/persistence-example5.xml"; + PersistenceUnitInfo[] info = reader.readPersistenceUnitInfos(resource); + + assertNotNull(info); + assertEquals(1, info.length); + assertEquals("OrderManagement5", info[0].getPersistenceUnitName()); + + assertEquals(2, info[0].getMappingFileNames().size()); + assertEquals("order1.xml", info[0].getMappingFileNames().get(0)); + assertEquals("order2.xml", info[0].getMappingFileNames().get(1)); + + assertEquals(2, info[0].getJarFileUrls().size()); + assertEquals(new ClassPathResource("order.jar").getURL(), info[0].getJarFileUrls().get(0)); + assertEquals(new ClassPathResource("order-supplemental.jar").getURL(), info[0].getJarFileUrls().get(1)); + + assertEquals("com.acme.AcmePersistence", info[0].getPersistenceProviderClassName()); + assertEquals(0, info[0].getProperties().keySet().size()); + } + + public void testExampleComplex() throws Exception { + DataSource ds = new DriverManagerDataSource(); + + String resource = "/org/springframework/orm/jpa/persistence-complex.xml"; + MapDataSourceLookup dataSourceLookup = new MapDataSourceLookup(); + Map dataSources = new HashMap(); + dataSources.put("jdbc/MyPartDB", ds); + dataSources.put("jdbc/MyDB", ds); + dataSourceLookup.setDataSources(dataSources); + PersistenceUnitReader reader = new PersistenceUnitReader( + new PathMatchingResourcePatternResolver(), dataSourceLookup); + PersistenceUnitInfo[] info = reader.readPersistenceUnitInfos(resource); + + assertEquals(2, info.length); + + PersistenceUnitInfo pu1 = info[0]; + + assertEquals("pu1", pu1.getPersistenceUnitName()); + + assertEquals("com.acme.AcmePersistence", pu1.getPersistenceProviderClassName()); + + assertEquals(1, pu1.getMappingFileNames().size()); + assertEquals("ormap2.xml", pu1.getMappingFileNames().get(0)); + + assertEquals(1, pu1.getJarFileUrls().size()); + assertEquals(new ClassPathResource("order.jar").getURL(), pu1.getJarFileUrls().get(0)); + + // TODO need to check the default? Where is this defined + assertFalse(pu1.excludeUnlistedClasses()); + + assertSame(PersistenceUnitTransactionType.RESOURCE_LOCAL, pu1.getTransactionType()); + + Properties props = pu1.getProperties(); + assertEquals(2, props.keySet().size()); + assertEquals("on", props.getProperty("com.acme.persistence.sql-logging")); + assertEquals("bar", props.getProperty("foo")); + + assertNull(pu1.getNonJtaDataSource()); + + assertSame(ds, pu1.getJtaDataSource()); + + PersistenceUnitInfo pu2 = info[1]; + + assertSame(PersistenceUnitTransactionType.JTA, pu2.getTransactionType()); + assertEquals("com.acme.AcmePersistence", pu2.getPersistenceProviderClassName()); + + assertEquals(1, pu2.getMappingFileNames().size()); + assertEquals("order2.xml", pu2.getMappingFileNames().get(0)); + + assertEquals(1, pu2.getJarFileUrls().size()); + assertEquals(new ClassPathResource("order-supplemental.jar").getURL(), pu2.getJarFileUrls().get(0)); + assertTrue(pu2.excludeUnlistedClasses()); + + assertNull(pu2.getJtaDataSource()); + + // TODO need to define behaviour with non jta datasource + assertEquals(ds, pu2.getNonJtaDataSource()); + } + + public void testExample6() throws Exception { + PersistenceUnitReader reader = new PersistenceUnitReader( + new PathMatchingResourcePatternResolver(), new JndiDataSourceLookup()); + String resource = "/org/springframework/orm/jpa/persistence-example6.xml"; + PersistenceUnitInfo[] info = reader.readPersistenceUnitInfos(resource); + assertEquals(1, info.length); + assertEquals("pu", info[0].getPersistenceUnitName()); + assertEquals(0, info[0].getProperties().keySet().size()); + } + + public void testInvalidPersistence() throws Exception { + PersistenceUnitReader reader = new PersistenceUnitReader( + new PathMatchingResourcePatternResolver(), new JndiDataSourceLookup()); + String resource = "/org/springframework/orm/jpa/persistence-invalid.xml"; + try { + reader.readPersistenceUnitInfos(resource); + fail("expected invalid document exception"); + } + catch (RuntimeException expected) { + } + } + + public void testNoSchemaPersistence() throws Exception { + PersistenceUnitReader reader = new PersistenceUnitReader( + new PathMatchingResourcePatternResolver(), new JndiDataSourceLookup()); + String resource = "/org/springframework/orm/jpa/persistence-no-schema.xml"; + try { + reader.readPersistenceUnitInfos(resource); + fail("expected invalid document exception"); + } + catch (RuntimeException expected) { + } + } + + public void testPersistenceUnitRootUrl() throws Exception { + PersistenceUnitReader reader = new PersistenceUnitReader( + new PathMatchingResourcePatternResolver(), new JndiDataSourceLookup()); + + URL url = reader.determinePersistenceUnitRootUrl(new ClassPathResource( + "/org/springframework/orm/jpa/persistence-no-schema.xml")); + assertNull(url); + + url = reader.determinePersistenceUnitRootUrl(new ClassPathResource("/org/springframework/orm/jpa/META-INF/persistence.xml")); + assertTrue("the containing folder should have been returned", url.toString().endsWith("/org/springframework/orm/jpa/")); + } + + public void testPersistenceUnitRootUrlWithJar() throws Exception { + PersistenceUnitReader reader = new PersistenceUnitReader( + new PathMatchingResourcePatternResolver(), new JndiDataSourceLookup()); + + ClassPathResource archive = new ClassPathResource("/org/springframework/orm/jpa/jpa-archive.jar"); + String newRoot = "jar:" + archive.getURL().toExternalForm() + "!/META-INF/persist.xml"; + Resource insideArchive = new UrlResource(newRoot); + // make sure the location actually exists + assertTrue(insideArchive.exists()); + URL url = reader.determinePersistenceUnitRootUrl(insideArchive); + assertTrue("the archive location should have been returned", archive.getURL().sameFile(url)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/JpaDaoSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/JpaDaoSupportTests.java new file mode 100644 index 00000000000..e5513a0cf5d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/JpaDaoSupportTests.java @@ -0,0 +1,98 @@ +/* + * Copyright 2002-2006 the original author 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.orm.jpa.support; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; + +import junit.framework.TestCase; + +import org.easymock.MockControl; +import org.springframework.orm.jpa.JpaTemplate; + +/** + * @author Costin Leau + * + */ +public class JpaDaoSupportTests extends TestCase { + + public void testJpaDaoSupportWithEntityManager() throws Exception { + MockControl mockControl = MockControl.createControl(EntityManager.class); + EntityManager entityManager = (EntityManager) mockControl.getMock(); + mockControl.replay(); + final List test = new ArrayList(); + JpaDaoSupport dao = new JpaDaoSupport() { + protected void initDao() { + test.add("test"); + } + }; + dao.setEntityManager(entityManager); + dao.afterPropertiesSet(); + assertNotNull("jpa template not created", dao.getJpaTemplate()); + assertEquals("incorrect entity manager", entityManager, dao.getJpaTemplate().getEntityManager()); + assertEquals("initDao not called", test.size(), 1); + mockControl.verify(); + } + + public void testJpaDaoSupportWithEntityManagerFactory() throws Exception { + MockControl mockControl = MockControl.createControl(EntityManagerFactory.class); + EntityManagerFactory entityManagerFactory = (EntityManagerFactory) mockControl.getMock(); + mockControl.replay(); + final List test = new ArrayList(); + JpaDaoSupport dao = new JpaDaoSupport() { + protected void initDao() { + test.add("test"); + } + }; + dao.setEntityManagerFactory(entityManagerFactory); + dao.afterPropertiesSet(); + assertNotNull("jpa template not created", dao.getJpaTemplate()); + assertEquals("incorrect entity manager factory", entityManagerFactory, + dao.getJpaTemplate().getEntityManagerFactory()); + assertEquals("initDao not called", test.size(), 1); + mockControl.verify(); + } + + public void testJpaDaoSupportWithJpaTemplate() throws Exception { + JpaTemplate template = new JpaTemplate(); + final List test = new ArrayList(); + JpaDaoSupport dao = new JpaDaoSupport() { + protected void initDao() { + test.add("test"); + } + }; + dao.setJpaTemplate(template); + dao.afterPropertiesSet(); + assertNotNull("jpa template not created", dao.getJpaTemplate()); + assertEquals("incorrect JpaTemplate", template, dao.getJpaTemplate()); + assertEquals("initDao not called", test.size(), 1); + } + + public void testInvalidJpaTemplate() throws Exception { + JpaDaoSupport dao = new JpaDaoSupport() { + }; + try { + dao.afterPropertiesSet(); + fail("expected exception"); + } + catch (IllegalArgumentException iae) { + // okay + } + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewTests.java new file mode 100644 index 00000000000..852ab3118f1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewTests.java @@ -0,0 +1,206 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa.support; + +import java.io.IOException; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; +import org.springframework.mock.web.PassThroughFilterChain; +import org.springframework.orm.jpa.JpaTemplate; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter; + +/** + * @author Costin Leau + * @author Juergen Hoeller + */ +public class OpenEntityManagerInViewTests extends TestCase { + + private MockControl factoryControl, managerControl; + + private EntityManager manager; + + private EntityManagerFactory factory; + + private JpaTemplate template; + + + @Override + protected void setUp() throws Exception { + factoryControl = MockControl.createControl(EntityManagerFactory.class); + factory = (EntityManagerFactory) factoryControl.getMock(); + managerControl = MockControl.createControl(EntityManager.class); + manager = (EntityManager) managerControl.getMock(); + + template = new JpaTemplate(factory); + template.afterPropertiesSet(); + + factoryControl.expectAndReturn(factory.createEntityManager(), manager); + } + + @Override + protected void tearDown() throws Exception { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + } + + public void testOpenEntityManagerInterceptorInView() throws Exception { + OpenEntityManagerInViewInterceptor rawInterceptor = new OpenEntityManagerInViewInterceptor(); + rawInterceptor.setEntityManagerFactory(factory); + HandlerInterceptor interceptor = new WebRequestHandlerInterceptorAdapter(rawInterceptor); + + MockServletContext sc = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(sc); + MockHttpServletResponse response = new MockHttpServletResponse(); + + managerControl.replay(); + factoryControl.replay(); + + interceptor.preHandle(request, response, "handler"); + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + + // check that further invocations simply participate + interceptor.preHandle(request, response, "handler"); + + interceptor.preHandle(request, response, "handler"); + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + interceptor.preHandle(request, response, "handler"); + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + factoryControl.verify(); + managerControl.verify(); + + managerControl.reset(); + factoryControl.reset(); + managerControl.replay(); + factoryControl.replay(); + + interceptor.postHandle(request, response, "handler", null); + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + + factoryControl.verify(); + managerControl.verify(); + + managerControl.reset(); + factoryControl.reset(); + + manager.close(); + + managerControl.replay(); + factoryControl.replay(); + + interceptor.afterCompletion(request, response, "handler", null); + assertFalse(TransactionSynchronizationManager.hasResource(factory)); + + factoryControl.verify(); + managerControl.verify(); + } + + public void testOpenEntityManagerInViewFilter() throws Exception { + manager.close(); + + managerControl.replay(); + factoryControl.replay(); + + MockControl factoryControl2 = MockControl.createControl(EntityManagerFactory.class); + final EntityManagerFactory factory2 = (EntityManagerFactory) factoryControl2.getMock(); + + MockControl managerControl2 = MockControl.createControl(EntityManager.class); + EntityManager manager2 = (EntityManager) managerControl2.getMock(); + + factoryControl2.expectAndReturn(factory2.createEntityManager(), manager2); + manager2.close(); + + factoryControl2.replay(); + managerControl2.replay(); + + MockServletContext sc = new MockServletContext(); + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + wac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory", factory); + wac.getDefaultListableBeanFactory().registerSingleton("myEntityManagerFactory", factory2); + wac.refresh(); + sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + MockHttpServletRequest request = new MockHttpServletRequest(sc); + MockHttpServletResponse response = new MockHttpServletResponse(); + + MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter"); + MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2"); + filterConfig2.addInitParameter("entityManagerFactoryBeanName", "myEntityManagerFactory"); + + final OpenEntityManagerInViewFilter filter = new OpenEntityManagerInViewFilter(); + filter.init(filterConfig); + final OpenEntityManagerInViewFilter filter2 = new OpenEntityManagerInViewFilter(); + filter2.init(filterConfig2); + + final FilterChain filterChain = new FilterChain() { + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) { + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + servletRequest.setAttribute("invoked", Boolean.TRUE); + } + }; + + final FilterChain filterChain2 = new FilterChain() { + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) + throws IOException, ServletException { + assertTrue(TransactionSynchronizationManager.hasResource(factory2)); + filter.doFilter(servletRequest, servletResponse, filterChain); + } + }; + + FilterChain filterChain3 = new PassThroughFilterChain(filter2, filterChain2); + + assertFalse(TransactionSynchronizationManager.hasResource(factory)); + assertFalse(TransactionSynchronizationManager.hasResource(factory2)); + filter2.doFilter(request, response, filterChain3); + assertFalse(TransactionSynchronizationManager.hasResource(factory)); + assertFalse(TransactionSynchronizationManager.hasResource(factory2)); + assertNotNull(request.getAttribute("invoked")); + + factoryControl.verify(); + managerControl.verify(); + factoryControl2.verify(); + managerControl2.verify(); + + wac.close(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/PersistenceInjectionIntegrationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/PersistenceInjectionIntegrationTests.java new file mode 100644 index 00000000000..5c598e00c99 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/PersistenceInjectionIntegrationTests.java @@ -0,0 +1,63 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa.support; + +import javax.persistence.EntityManager; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.orm.jpa.AbstractEntityManagerFactoryIntegrationTests; +import org.springframework.orm.jpa.support.PersistenceInjectionTests.DefaultPublicPersistenceContextSetter; +import org.springframework.orm.jpa.support.PersistenceInjectionTests.DefaultPublicPersistenceUnitSetterNamedPerson; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class PersistenceInjectionIntegrationTests extends AbstractEntityManagerFactoryIntegrationTests { + + @Autowired + private DefaultPublicPersistenceContextSetter defaultSetterInjected; + + private DefaultPublicPersistenceUnitSetterNamedPerson namedSetterInjected; + + + public PersistenceInjectionIntegrationTests() { + setAutowireMode(AUTOWIRE_NO); + setDependencyCheck(false); + } + + @Autowired + private void init(DefaultPublicPersistenceUnitSetterNamedPerson namedSetterInjected) { + this.namedSetterInjected = namedSetterInjected; + } + + + public void testDefaultSetterInjection() { + EntityManager injectedEm = defaultSetterInjected.getEntityManager(); + assertNotNull("Default PersistenceContext Setter was injected", injectedEm); + } + + public void testInjectedEntityManagerImplmentsPortableEntityManagerPlus() { + EntityManager injectedEm = defaultSetterInjected.getEntityManager(); + assertNotNull("Default PersistenceContext Setter was injected", injectedEm); + } + + public void testSetterInjectionOfNamedPersistenceContext() { + assertNotNull("Named PersistenceContext Setter was injected", namedSetterInjected.getEntityManagerFactory()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/PersistenceInjectionTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/PersistenceInjectionTests.java new file mode 100644 index 00000000000..b300c1bdb0f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/PersistenceInjectionTests.java @@ -0,0 +1,843 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa.support; + +import java.io.Serializable; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.PersistenceContext; +import javax.persistence.PersistenceContextType; +import javax.persistence.PersistenceProperty; +import javax.persistence.PersistenceUnit; + +import org.easymock.MockControl; +import org.hibernate.ejb.HibernateEntityManager; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.config.SimpleMapScope; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.mock.jndi.ExpectedLookupTemplate; +import org.springframework.orm.jpa.AbstractEntityManagerFactoryBeanTests; +import org.springframework.orm.jpa.DefaultJpaDialect; +import org.springframework.orm.jpa.EntityManagerFactoryInfo; +import org.springframework.orm.jpa.EntityManagerHolder; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.util.SerializationTestUtils; + +/** + * Unit tests for persistence context and persistence unit injection. + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class PersistenceInjectionTests extends AbstractEntityManagerFactoryBeanTests { + + public void testPrivatePersistenceContextField() { + GenericApplicationContext gac = new GenericApplicationContext(); + gac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory", mockEmf); + gac.registerBeanDefinition("annotationProcessor", + new RootBeanDefinition(PersistenceAnnotationBeanPostProcessor.class)); + gac.registerBeanDefinition(DefaultPrivatePersistenceContextField.class.getName(), + new RootBeanDefinition(DefaultPrivatePersistenceContextField.class)); + gac.registerBeanDefinition(FactoryBeanWithPersistenceContextField.class.getName(), + new RootBeanDefinition(FactoryBeanWithPersistenceContextField.class)); + gac.refresh(); + + DefaultPrivatePersistenceContextField bean = (DefaultPrivatePersistenceContextField) gac.getBean( + DefaultPrivatePersistenceContextField.class.getName()); + FactoryBeanWithPersistenceContextField bean2 = (FactoryBeanWithPersistenceContextField) gac.getBean( + "&" + FactoryBeanWithPersistenceContextField.class.getName()); + assertNotNull(bean.em); + assertNotNull(bean2.em); + } + + public void testPrivateVendorSpecificPersistenceContextField() { + GenericApplicationContext gac = new GenericApplicationContext(); + gac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory", mockEmf); + gac.registerBeanDefinition("annotationProcessor", + new RootBeanDefinition(PersistenceAnnotationBeanPostProcessor.class)); + gac.registerBeanDefinition(DefaultVendorSpecificPrivatePersistenceContextField.class.getName(), + new RootBeanDefinition(DefaultVendorSpecificPrivatePersistenceContextField.class)); + gac.refresh(); + + DefaultVendorSpecificPrivatePersistenceContextField bean = (DefaultVendorSpecificPrivatePersistenceContextField) + gac.getBean(DefaultVendorSpecificPrivatePersistenceContextField.class.getName()); + assertNotNull(bean.em); + } + + public void testPublicExtendedPersistenceContextSetter() throws Exception { + Object mockEm = (EntityManager) MockControl.createControl(EntityManager.class).getMock(); + mockEmf.createEntityManager(); + emfMc.setReturnValue(mockEm, 1); + emfMc.replay(); + + GenericApplicationContext gac = new GenericApplicationContext(); + gac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory", mockEmf); + gac.registerBeanDefinition("annotationProcessor", + new RootBeanDefinition(PersistenceAnnotationBeanPostProcessor.class)); + gac.registerBeanDefinition(DefaultPublicPersistenceContextSetter.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceContextSetter.class)); + gac.refresh(); + + DefaultPublicPersistenceContextSetter bean = (DefaultPublicPersistenceContextSetter) gac.getBean( + DefaultPublicPersistenceContextSetter.class.getName()); + assertNotNull(bean.em); + emfMc.verify(); + } + + public void testPublicExtendedPersistenceContextSetterWithSerialization() throws Exception { + DummyInvocationHandler ih = new DummyInvocationHandler(); + Object mockEm = (EntityManager) Proxy.newProxyInstance( + getClass().getClassLoader(), new Class[] {EntityManager.class}, ih); + mockEmf.createEntityManager(); + emfMc.setReturnValue(mockEm, 1); + emfMc.replay(); + + GenericApplicationContext gac = new GenericApplicationContext(); + SimpleMapScope myScope = new SimpleMapScope(); + gac.getDefaultListableBeanFactory().registerScope("myScope", myScope); + gac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory", mockEmf); + gac.registerBeanDefinition("annotationProcessor", + new RootBeanDefinition(PersistenceAnnotationBeanPostProcessor.class)); + RootBeanDefinition bd = new RootBeanDefinition(DefaultPublicPersistenceContextSetter.class); + bd.setScope("myScope"); + gac.registerBeanDefinition(DefaultPublicPersistenceContextSetter.class.getName(), bd); + gac.refresh(); + + DefaultPublicPersistenceContextSetter bean = (DefaultPublicPersistenceContextSetter) gac.getBean( + DefaultPublicPersistenceContextSetter.class.getName()); + assertNotNull(bean.em); + assertNotNull(SerializationTestUtils.serializeAndDeserialize(bean.em)); + + SimpleMapScope serialized = (SimpleMapScope) SerializationTestUtils.serializeAndDeserialize(myScope); + serialized.close(); + assertTrue(DummyInvocationHandler.closed); + DummyInvocationHandler.closed = false; + emfMc.verify(); + } + + public void testPublicExtendedPersistenceContextSetterWithEntityManagerInfoAndSerialization() throws Exception { + Object mockEm = (EntityManager) Proxy.newProxyInstance( + getClass().getClassLoader(), new Class[] {EntityManager.class}, new DummyInvocationHandler()); + MockControl emfMc = MockControl.createControl(EntityManagerFactoryWithInfo.class); + EntityManagerFactoryWithInfo mockEmf = (EntityManagerFactoryWithInfo) emfMc.getMock(); + mockEmf.getNativeEntityManagerFactory(); + emfMc.setReturnValue(mockEmf); + mockEmf.getPersistenceUnitInfo(); + emfMc.setReturnValue(null); + mockEmf.getJpaDialect(); + emfMc.setReturnValue(new DefaultJpaDialect()); + mockEmf.getEntityManagerInterface(); + emfMc.setReturnValue(EntityManager.class); + mockEmf.getBeanClassLoader(); + emfMc.setReturnValue(getClass().getClassLoader()); + mockEmf.createEntityManager(); + emfMc.setReturnValue(mockEm); + emfMc.replay(); + + GenericApplicationContext gac = new GenericApplicationContext(); + gac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory", mockEmf); + gac.registerBeanDefinition("annotationProcessor", + new RootBeanDefinition(PersistenceAnnotationBeanPostProcessor.class)); + gac.registerBeanDefinition(DefaultPublicPersistenceContextSetter.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceContextSetter.class)); + gac.refresh(); + + DefaultPublicPersistenceContextSetter bean = (DefaultPublicPersistenceContextSetter) gac.getBean( + DefaultPublicPersistenceContextSetter.class.getName()); + assertNotNull(bean.em); + assertNotNull(SerializationTestUtils.serializeAndDeserialize(bean.em)); + emfMc.verify(); + } + + public void testPublicExtendedPersistenceContextSetterWithOverriding() { + EntityManager mockEm2 = (EntityManager) MockControl.createControl(EntityManager.class).getMock(); + + GenericApplicationContext gac = new GenericApplicationContext(); + gac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory", mockEmf); + gac.registerBeanDefinition("annotationProcessor", + new RootBeanDefinition(PersistenceAnnotationBeanPostProcessor.class)); + RootBeanDefinition bd = new RootBeanDefinition(DefaultPublicPersistenceContextSetter.class); + bd.getPropertyValues().addPropertyValue("entityManager", mockEm2); + gac.registerBeanDefinition(DefaultPublicPersistenceContextSetter.class.getName(), bd); + gac.refresh(); + + DefaultPublicPersistenceContextSetter bean = (DefaultPublicPersistenceContextSetter) gac.getBean( + DefaultPublicPersistenceContextSetter.class.getName()); + assertSame(mockEm2, bean.em); + } + + public void testPrivatePersistenceUnitField() { + GenericApplicationContext gac = new GenericApplicationContext(); + gac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory", mockEmf); + gac.registerBeanDefinition("annotationProcessor", + new RootBeanDefinition(PersistenceAnnotationBeanPostProcessor.class)); + gac.registerBeanDefinition(DefaultPrivatePersistenceUnitField.class.getName(), + new RootBeanDefinition(DefaultPrivatePersistenceUnitField.class)); + gac.refresh(); + + DefaultPrivatePersistenceUnitField bean = (DefaultPrivatePersistenceUnitField) gac.getBean( + DefaultPrivatePersistenceUnitField.class.getName()); + assertSame(mockEmf, bean.emf); + } + + public void testPublicPersistenceUnitSetter() { + GenericApplicationContext gac = new GenericApplicationContext(); + gac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory", mockEmf); + gac.registerBeanDefinition("annotationProcessor", + new RootBeanDefinition(PersistenceAnnotationBeanPostProcessor.class)); + gac.registerBeanDefinition(DefaultPublicPersistenceUnitSetter.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceUnitSetter.class)); + gac.refresh(); + + DefaultPublicPersistenceUnitSetter bean = (DefaultPublicPersistenceUnitSetter) gac.getBean( + DefaultPublicPersistenceUnitSetter.class.getName()); + assertSame(mockEmf, bean.emf); + } + + public void testPublicPersistenceUnitSetterWithOverriding() { + EntityManagerFactory mockEmf2 = + (EntityManagerFactory) MockControl.createControl(EntityManagerFactory.class).getMock(); + + GenericApplicationContext gac = new GenericApplicationContext(); + gac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory", mockEmf); + gac.registerBeanDefinition("annotationProcessor", + new RootBeanDefinition(PersistenceAnnotationBeanPostProcessor.class)); + RootBeanDefinition bd = new RootBeanDefinition(DefaultPublicPersistenceUnitSetter.class); + bd.getPropertyValues().addPropertyValue("emf", mockEmf2); + gac.registerBeanDefinition(DefaultPublicPersistenceUnitSetter.class.getName(), bd); + gac.refresh(); + + DefaultPublicPersistenceUnitSetter bean = (DefaultPublicPersistenceUnitSetter) gac.getBean( + DefaultPublicPersistenceUnitSetter.class.getName()); + assertSame(mockEmf2, bean.emf); + } + + public void testPublicPersistenceUnitSetterWithUnitIdentifiedThroughBeanName() { + EntityManagerFactory mockEmf2 = + (EntityManagerFactory) MockControl.createControl(EntityManagerFactory.class).getMock(); + + GenericApplicationContext gac = new GenericApplicationContext(); + gac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory", mockEmf); + gac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory2", mockEmf2); + gac.registerAlias("entityManagerFactory2", "Person"); + RootBeanDefinition processorDef = new RootBeanDefinition(PersistenceAnnotationBeanPostProcessor.class); + processorDef.getPropertyValues().addPropertyValue("defaultPersistenceUnitName", "entityManagerFactory"); + gac.registerBeanDefinition("annotationProcessor", processorDef); + gac.registerBeanDefinition(DefaultPublicPersistenceUnitSetter.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceUnitSetter.class)); + gac.registerBeanDefinition(DefaultPublicPersistenceUnitSetterNamedPerson.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceUnitSetterNamedPerson.class)); + gac.refresh(); + + DefaultPublicPersistenceUnitSetter bean = (DefaultPublicPersistenceUnitSetter) + gac.getBean(DefaultPublicPersistenceUnitSetter.class.getName()); + DefaultPublicPersistenceUnitSetterNamedPerson bean2 = (DefaultPublicPersistenceUnitSetterNamedPerson) + gac.getBean(DefaultPublicPersistenceUnitSetterNamedPerson.class.getName()); + assertSame(mockEmf, bean.emf); + assertSame(mockEmf2, bean2.emf); + } + + public void testPublicPersistenceUnitSetterWithMultipleUnitsIdentifiedThroughUnitName() { + MockControl emf2Mc = MockControl.createControl(EntityManagerFactoryWithInfo.class); + EntityManagerFactoryWithInfo mockEmf2 = (EntityManagerFactoryWithInfo) emf2Mc.getMock(); + mockEmf2.getPersistenceUnitName(); + emf2Mc.setReturnValue("Person", 2); + emf2Mc.replay(); + + GenericApplicationContext gac = new GenericApplicationContext(); + gac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory", mockEmf); + gac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory2", mockEmf2); + RootBeanDefinition processorDef = new RootBeanDefinition(PersistenceAnnotationBeanPostProcessor.class); + processorDef.getPropertyValues().addPropertyValue("defaultPersistenceUnitName", "entityManagerFactory"); + gac.registerBeanDefinition("annotationProcessor", processorDef); + gac.registerBeanDefinition(DefaultPublicPersistenceUnitSetter.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceUnitSetter.class)); + gac.registerBeanDefinition(DefaultPublicPersistenceUnitSetterNamedPerson.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceUnitSetterNamedPerson.class)); + gac.refresh(); + + DefaultPublicPersistenceUnitSetter bean = (DefaultPublicPersistenceUnitSetter) + gac.getBean(DefaultPublicPersistenceUnitSetter.class.getName()); + DefaultPublicPersistenceUnitSetterNamedPerson bean2 = (DefaultPublicPersistenceUnitSetterNamedPerson) + gac.getBean(DefaultPublicPersistenceUnitSetterNamedPerson.class.getName()); + assertSame(mockEmf, bean.emf); + assertSame(mockEmf2, bean2.emf); + + emf2Mc.verify(); + } + + public void testPersistenceUnitsFromJndi() { + mockEmf.createEntityManager(); + Object mockEm = (EntityManager) MockControl.createControl(EntityManager.class).getMock(); + emfMc.setReturnValue(mockEm, 1); + emfMc.replay(); + + MockControl emf2Mc = MockControl.createControl(EntityManagerFactoryWithInfo.class); + EntityManagerFactoryWithInfo mockEmf2 = (EntityManagerFactoryWithInfo) emf2Mc.getMock(); + + Map persistenceUnits = new HashMap(); + persistenceUnits.put("", "pu1"); + persistenceUnits.put("Person", "pu2"); + ExpectedLookupTemplate jt = new ExpectedLookupTemplate(); + jt.addObject("java:comp/env/pu1", mockEmf); + jt.addObject("java:comp/env/pu2", mockEmf2); + + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + PersistenceAnnotationBeanPostProcessor bpp = new PersistenceAnnotationBeanPostProcessor(); + bpp.setPersistenceUnits(persistenceUnits); + bpp.setJndiTemplate(jt); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition(DefaultPublicPersistenceUnitSetter.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceUnitSetter.class)); + bf.registerBeanDefinition(DefaultPublicPersistenceUnitSetterNamedPerson.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceUnitSetterNamedPerson.class)); + bf.registerBeanDefinition(DefaultPrivatePersistenceContextField.class.getName(), + new RootBeanDefinition(DefaultPrivatePersistenceContextField.class)); + bf.registerBeanDefinition(DefaultPublicPersistenceContextSetter.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceContextSetter.class)); + + DefaultPublicPersistenceUnitSetter bean = (DefaultPublicPersistenceUnitSetter) + bf.getBean(DefaultPublicPersistenceUnitSetter.class.getName()); + DefaultPublicPersistenceUnitSetterNamedPerson bean2 = (DefaultPublicPersistenceUnitSetterNamedPerson) + bf.getBean(DefaultPublicPersistenceUnitSetterNamedPerson.class.getName()); + DefaultPrivatePersistenceContextField bean3 = (DefaultPrivatePersistenceContextField) + bf.getBean(DefaultPrivatePersistenceContextField.class.getName()); + DefaultPublicPersistenceContextSetter bean4 = (DefaultPublicPersistenceContextSetter) + bf.getBean(DefaultPublicPersistenceContextSetter.class.getName()); + assertSame(mockEmf, bean.emf); + assertSame(mockEmf2, bean2.emf); + assertNotNull(bean3.em); + assertNotNull(bean4.em); + + emfMc.verify(); + } + + public void testPersistenceUnitsFromJndiWithDefaultUnit() { + MockControl emf2Mc = MockControl.createControl(EntityManagerFactoryWithInfo.class); + EntityManagerFactoryWithInfo mockEmf2 = (EntityManagerFactoryWithInfo) emf2Mc.getMock(); + + Map persistenceUnits = new HashMap(); + persistenceUnits.put("System", "pu1"); + persistenceUnits.put("Person", "pu2"); + ExpectedLookupTemplate jt = new ExpectedLookupTemplate(); + jt.addObject("java:comp/env/pu1", mockEmf); + jt.addObject("java:comp/env/pu2", mockEmf2); + + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + PersistenceAnnotationBeanPostProcessor bpp = new PersistenceAnnotationBeanPostProcessor(); + bpp.setPersistenceUnits(persistenceUnits); + bpp.setDefaultPersistenceUnitName("System"); + bpp.setJndiTemplate(jt); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition(DefaultPublicPersistenceUnitSetter.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceUnitSetter.class)); + bf.registerBeanDefinition(DefaultPublicPersistenceUnitSetterNamedPerson.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceUnitSetterNamedPerson.class)); + + DefaultPublicPersistenceUnitSetter bean = (DefaultPublicPersistenceUnitSetter) + bf.getBean(DefaultPublicPersistenceUnitSetter.class.getName()); + DefaultPublicPersistenceUnitSetterNamedPerson bean2 = (DefaultPublicPersistenceUnitSetterNamedPerson) + bf.getBean(DefaultPublicPersistenceUnitSetterNamedPerson.class.getName()); + assertSame(mockEmf, bean.emf); + assertSame(mockEmf2, bean2.emf); + } + + public void testSinglePersistenceUnitFromJndi() { + Map persistenceUnits = new HashMap(); + persistenceUnits.put("Person", "pu1"); + ExpectedLookupTemplate jt = new ExpectedLookupTemplate(); + jt.addObject("java:comp/env/pu1", mockEmf); + + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + PersistenceAnnotationBeanPostProcessor bpp = new PersistenceAnnotationBeanPostProcessor(); + bpp.setPersistenceUnits(persistenceUnits); + bpp.setJndiTemplate(jt); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition(DefaultPublicPersistenceUnitSetter.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceUnitSetter.class)); + bf.registerBeanDefinition(DefaultPublicPersistenceUnitSetterNamedPerson.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceUnitSetterNamedPerson.class)); + + DefaultPublicPersistenceUnitSetter bean = (DefaultPublicPersistenceUnitSetter) + bf.getBean(DefaultPublicPersistenceUnitSetter.class.getName()); + DefaultPublicPersistenceUnitSetterNamedPerson bean2 = (DefaultPublicPersistenceUnitSetterNamedPerson) + bf.getBean(DefaultPublicPersistenceUnitSetterNamedPerson.class.getName()); + assertSame(mockEmf, bean.emf); + assertSame(mockEmf, bean2.emf); + } + + public void testPersistenceContextsFromJndi() { + Object mockEm = (EntityManager) MockControl.createControl(EntityManager.class).getMock(); + Object mockEm2 = (EntityManager) MockControl.createControl(EntityManager.class).getMock(); + Object mockEm3 = (EntityManager) MockControl.createControl(EntityManager.class).getMock(); + + Map persistenceContexts = new HashMap(); + persistenceContexts.put("", "pc1"); + persistenceContexts.put("Person", "pc2"); + Map extendedPersistenceContexts = new HashMap(); + extendedPersistenceContexts .put("", "pc3"); + ExpectedLookupTemplate jt = new ExpectedLookupTemplate(); + jt.addObject("java:comp/env/pc1", mockEm); + jt.addObject("java:comp/env/pc2", mockEm2); + jt.addObject("java:comp/env/pc3", mockEm3); + + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + PersistenceAnnotationBeanPostProcessor bpp = new PersistenceAnnotationBeanPostProcessor(); + bpp.setPersistenceContexts(persistenceContexts); + bpp.setExtendedPersistenceContexts(extendedPersistenceContexts); + bpp.setJndiTemplate(jt); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition(DefaultPrivatePersistenceContextField.class.getName(), + new RootBeanDefinition(DefaultPrivatePersistenceContextField.class)); + bf.registerBeanDefinition(DefaultPrivatePersistenceContextFieldNamedPerson.class.getName(), + new RootBeanDefinition(DefaultPrivatePersistenceContextFieldNamedPerson.class)); + bf.registerBeanDefinition(DefaultPublicPersistenceContextSetter.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceContextSetter.class)); + + DefaultPrivatePersistenceContextField bean1 = (DefaultPrivatePersistenceContextField) + bf.getBean(DefaultPrivatePersistenceContextField.class.getName()); + DefaultPrivatePersistenceContextFieldNamedPerson bean2 = (DefaultPrivatePersistenceContextFieldNamedPerson) + bf.getBean(DefaultPrivatePersistenceContextFieldNamedPerson.class.getName()); + DefaultPublicPersistenceContextSetter bean3 = (DefaultPublicPersistenceContextSetter) + bf.getBean(DefaultPublicPersistenceContextSetter.class.getName()); + assertSame(mockEm, bean1.em); + assertSame(mockEm2, bean2.em); + assertSame(mockEm3, bean3.em); + } + + public void testPersistenceContextsFromJndiWithDefaultUnit() { + Object mockEm = (EntityManager) MockControl.createControl(EntityManager.class).getMock(); + Object mockEm2 = (EntityManager) MockControl.createControl(EntityManager.class).getMock(); + Object mockEm3 = (EntityManager) MockControl.createControl(EntityManager.class).getMock(); + + Map persistenceContexts = new HashMap(); + persistenceContexts.put("System", "pc1"); + persistenceContexts.put("Person", "pc2"); + Map extendedPersistenceContexts = new HashMap(); + extendedPersistenceContexts .put("System", "pc3"); + ExpectedLookupTemplate jt = new ExpectedLookupTemplate(); + jt.addObject("java:comp/env/pc1", mockEm); + jt.addObject("java:comp/env/pc2", mockEm2); + jt.addObject("java:comp/env/pc3", mockEm3); + + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + PersistenceAnnotationBeanPostProcessor bpp = new PersistenceAnnotationBeanPostProcessor(); + bpp.setPersistenceContexts(persistenceContexts); + bpp.setExtendedPersistenceContexts(extendedPersistenceContexts); + bpp.setDefaultPersistenceUnitName("System"); + bpp.setJndiTemplate(jt); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition(DefaultPrivatePersistenceContextField.class.getName(), + new RootBeanDefinition(DefaultPrivatePersistenceContextField.class)); + bf.registerBeanDefinition(DefaultPrivatePersistenceContextFieldNamedPerson.class.getName(), + new RootBeanDefinition(DefaultPrivatePersistenceContextFieldNamedPerson.class)); + bf.registerBeanDefinition(DefaultPublicPersistenceContextSetter.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceContextSetter.class)); + + DefaultPrivatePersistenceContextField bean1 = (DefaultPrivatePersistenceContextField) + bf.getBean(DefaultPrivatePersistenceContextField.class.getName()); + DefaultPrivatePersistenceContextFieldNamedPerson bean2 = (DefaultPrivatePersistenceContextFieldNamedPerson) + bf.getBean(DefaultPrivatePersistenceContextFieldNamedPerson.class.getName()); + DefaultPublicPersistenceContextSetter bean3 = (DefaultPublicPersistenceContextSetter) + bf.getBean(DefaultPublicPersistenceContextSetter.class.getName()); + assertSame(mockEm, bean1.em); + assertSame(mockEm2, bean2.em); + assertSame(mockEm3, bean3.em); + } + + public void testSinglePersistenceContextFromJndi() { + Object mockEm = (EntityManager) MockControl.createControl(EntityManager.class).getMock(); + Object mockEm2 = (EntityManager) MockControl.createControl(EntityManager.class).getMock(); + + Map persistenceContexts = new HashMap(); + persistenceContexts.put("System", "pc1"); + Map extendedPersistenceContexts = new HashMap(); + extendedPersistenceContexts .put("System", "pc2"); + ExpectedLookupTemplate jt = new ExpectedLookupTemplate(); + jt.addObject("java:comp/env/pc1", mockEm); + jt.addObject("java:comp/env/pc2", mockEm2); + + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + PersistenceAnnotationBeanPostProcessor bpp = new PersistenceAnnotationBeanPostProcessor(); + bpp.setPersistenceContexts(persistenceContexts); + bpp.setExtendedPersistenceContexts(extendedPersistenceContexts); + bpp.setJndiTemplate(jt); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition(DefaultPrivatePersistenceContextField.class.getName(), + new RootBeanDefinition(DefaultPrivatePersistenceContextField.class)); + bf.registerBeanDefinition(DefaultPublicPersistenceContextSetter.class.getName(), + new RootBeanDefinition(DefaultPublicPersistenceContextSetter.class)); + + DefaultPrivatePersistenceContextField bean1 = (DefaultPrivatePersistenceContextField) + bf.getBean(DefaultPrivatePersistenceContextField.class.getName()); + DefaultPublicPersistenceContextSetter bean2 = (DefaultPublicPersistenceContextSetter) + bf.getBean(DefaultPublicPersistenceContextSetter.class.getName()); + assertSame(mockEm, bean1.em); + assertSame(mockEm2, bean2.em); + } + + public void testFieldOfWrongTypeAnnotatedWithPersistenceUnit() { + PersistenceAnnotationBeanPostProcessor babpp = new PersistenceAnnotationBeanPostProcessor(); + try { + babpp.postProcessAfterInstantiation(new FieldOfWrongTypeAnnotatedWithPersistenceUnit(), + "bean name does not matter"); + fail("Can't inject this field"); + } + catch (IllegalStateException ex) { + // Ok + } + } + + public void testSetterOfWrongTypeAnnotatedWithPersistenceUnit() { + PersistenceAnnotationBeanPostProcessor babpp = new PersistenceAnnotationBeanPostProcessor(); + try { + babpp.postProcessAfterInstantiation(new SetterOfWrongTypeAnnotatedWithPersistenceUnit(), + "bean name does not matter"); + fail("Can't inject this setter"); + } + catch (IllegalStateException ex) { + // Ok + } + } + + public void testSetterWithNoArgs() { + PersistenceAnnotationBeanPostProcessor babpp = new PersistenceAnnotationBeanPostProcessor(); + try { + babpp.postProcessAfterInstantiation(new SetterWithNoArgs(), "bean name does not matter"); + fail("Can't inject this setter"); + } + catch (IllegalStateException ex) { + // Ok + } + } + + public void testNoPropertiesPassedIn() { + mockEmf.createEntityManager(); + emfMc.setReturnValue(MockControl.createControl(EntityManager.class).getMock(), 1); + emfMc.replay(); + + PersistenceAnnotationBeanPostProcessor babpp = new MockPersistenceAnnotationBeanPostProcessor(); + DefaultPrivatePersistenceContextFieldExtended dppcf = new DefaultPrivatePersistenceContextFieldExtended(); + babpp.postProcessAfterInstantiation(dppcf, "bean name does not matter"); + assertNotNull(dppcf.em); + emfMc.verify(); + } + + public void testPropertiesPassedIn() { + Properties props = new Properties(); + props.put("foo", "bar"); + mockEmf.createEntityManager(props); + emfMc.setReturnValue(MockControl.createControl(EntityManager.class).getMock(), 1); + emfMc.replay(); + + PersistenceAnnotationBeanPostProcessor babpp = new MockPersistenceAnnotationBeanPostProcessor(); + DefaultPrivatePersistenceContextFieldExtendedWithProps dppcf = + new DefaultPrivatePersistenceContextFieldExtendedWithProps(); + babpp.postProcessAfterInstantiation(dppcf, "bean name does not matter"); + assertNotNull(dppcf.em); + emfMc.verify(); + } + + public void testPropertiesForTransactionalEntityManager() { + Properties props = new Properties(); + props.put("foo", "bar"); + MockControl emC = MockControl.createControl(EntityManager.class); + EntityManager em = (EntityManager) emC.getMock(); + emfMc.expectAndReturn(mockEmf.createEntityManager(props), em); + emC.expectAndReturn(em.getDelegate(), new Object()); + em.close(); + + emfMc.replay(); + emC.replay(); + + PersistenceAnnotationBeanPostProcessor babpp = new MockPersistenceAnnotationBeanPostProcessor(); + DefaultPrivatePersistenceContextFieldWithProperties transactionalField = + new DefaultPrivatePersistenceContextFieldWithProperties(); + babpp.postProcessAfterInstantiation(transactionalField, "bean name does not matter"); + + assertNotNull(transactionalField.em); + assertNotNull(transactionalField.em.getDelegate()); + + emfMc.verify(); + emC.verify(); + } + + /** + * Binds an EMF to the thread and tests if EM with different properties + * generate new EMs or not. + */ + public void testPropertiesForSharedEntityManager1() { + Properties props = new Properties(); + props.put("foo", "bar"); + MockControl emC = MockControl.createControl(EntityManager.class); + EntityManager em = (EntityManager) emC.getMock(); + // only one call made - the first EM definition wins (in this case the one w/ the properties) + emfMc.expectAndReturn(mockEmf.createEntityManager(props), em); + emC.expectAndReturn(em.getDelegate(), new Object(), 2); + em.close(); + + emfMc.replay(); + emC.replay(); + + PersistenceAnnotationBeanPostProcessor babpp = new MockPersistenceAnnotationBeanPostProcessor(); + DefaultPrivatePersistenceContextFieldWithProperties transactionalFieldWithProperties = + new DefaultPrivatePersistenceContextFieldWithProperties(); + DefaultPrivatePersistenceContextField transactionalField = new DefaultPrivatePersistenceContextField(); + + babpp.postProcessAfterInstantiation(transactionalFieldWithProperties, "bean name does not matter"); + babpp.postProcessAfterInstantiation(transactionalField, "bean name does not matter"); + + assertNotNull(transactionalFieldWithProperties.em); + assertNotNull(transactionalField.em); + // the EM w/ properties will be created + assertNotNull(transactionalFieldWithProperties.em.getDelegate()); + // bind em to the thread now since it's created + try { + TransactionSynchronizationManager.bindResource(mockEmf, new EntityManagerHolder(em)); + assertNotNull(transactionalField.em.getDelegate()); + emfMc.verify(); + emC.verify(); + } + finally { + TransactionSynchronizationManager.unbindResource(mockEmf); + } + } + + public void testPropertiesForSharedEntityManager2() { + Properties props = new Properties(); + props.put("foo", "bar"); + MockControl emC = MockControl.createControl(EntityManager.class); + EntityManager em = (EntityManager) emC.getMock(); + // only one call made - the first EM definition wins (in this case the one w/o the properties) + emfMc.expectAndReturn(mockEmf.createEntityManager(), em); + emC.expectAndReturn(em.getDelegate(), new Object(), 2); + em.close(); + + emfMc.replay(); + emC.replay(); + + PersistenceAnnotationBeanPostProcessor babpp = new MockPersistenceAnnotationBeanPostProcessor(); + DefaultPrivatePersistenceContextFieldWithProperties transactionalFieldWithProperties = + new DefaultPrivatePersistenceContextFieldWithProperties(); + DefaultPrivatePersistenceContextField transactionalField = new DefaultPrivatePersistenceContextField(); + + babpp.postProcessAfterInstantiation(transactionalFieldWithProperties, "bean name does not matter"); + babpp.postProcessAfterInstantiation(transactionalField, "bean name does not matter"); + + assertNotNull(transactionalFieldWithProperties.em); + assertNotNull(transactionalField.em); + // the EM w/o properties will be created + assertNotNull(transactionalField.em.getDelegate()); + // bind em to the thread now since it's created + try { + TransactionSynchronizationManager.bindResource(mockEmf, new EntityManagerHolder(em)); + assertNotNull(transactionalFieldWithProperties.em.getDelegate()); + emfMc.verify(); + emC.verify(); + } + finally { + TransactionSynchronizationManager.unbindResource(mockEmf); + } + } + + + private static class MockPersistenceAnnotationBeanPostProcessor extends PersistenceAnnotationBeanPostProcessor { + + @Override + protected EntityManagerFactory findEntityManagerFactory(String emfName, String requestingBeanName) { + return mockEmf; + } + } + + + public static class DefaultPrivatePersistenceContextField { + + @PersistenceContext + private EntityManager em; + } + + + public static class DefaultVendorSpecificPrivatePersistenceContextField { + + @PersistenceContext + private HibernateEntityManager em; + } + + + public static class FactoryBeanWithPersistenceContextField implements FactoryBean { + + @PersistenceContext + private EntityManager em; + + public Object getObject() throws Exception { + return null; + } + + public Class getObjectType() { + return null; + } + + public boolean isSingleton() { + return true; + } + } + + + public static class DefaultPrivatePersistenceContextFieldNamedPerson { + + @PersistenceContext(unitName = "Person") + private EntityManager em; + } + + + public static class DefaultPrivatePersistenceContextFieldWithProperties { + + @PersistenceContext(properties = { @PersistenceProperty(name = "foo", value = "bar") }) + private EntityManager em; + } + + + @Repository + public static class DefaultPublicPersistenceContextSetter implements Serializable { + + private EntityManager em; + + @PersistenceContext(type = PersistenceContextType.EXTENDED) + public void setEntityManager(EntityManager em) { + if (this.em != null) { + throw new IllegalStateException("Already called"); + } + this.em = em; + } + + public EntityManager getEntityManager() { + return em; + } + } + + + public static class DefaultPrivatePersistenceUnitField { + + @PersistenceUnit + private EntityManagerFactory emf; + } + + + public static class DefaultPublicPersistenceUnitSetter { + + private EntityManagerFactory emf; + + @PersistenceUnit + public void setEmf(EntityManagerFactory emf) { + if (this.emf != null) { + throw new IllegalStateException("Already called"); + } + this.emf = emf; + } + + public EntityManagerFactory getEmf() { + return emf; + } + } + + + @Repository + public static class DefaultPublicPersistenceUnitSetterNamedPerson { + + private EntityManagerFactory emf; + + @PersistenceUnit(unitName = "Person") + public void setEmf(EntityManagerFactory emf) { + this.emf = emf; + } + + public EntityManagerFactory getEntityManagerFactory() { + return emf; + } + } + + + public static class FieldOfWrongTypeAnnotatedWithPersistenceUnit { + + @PersistenceUnit + public String thisFieldIsOfTheWrongType; + } + + + public static class SetterOfWrongTypeAnnotatedWithPersistenceUnit { + + @PersistenceUnit + public void setSomething(Comparable c) { + } + } + + + public static class SetterWithNoArgs { + + @PersistenceUnit + public void setSomething() { + } + } + + + public static class DefaultPrivatePersistenceContextFieldExtended { + + @PersistenceContext(type = PersistenceContextType.EXTENDED) + private EntityManager em; + } + + + public static class DefaultPrivatePersistenceContextFieldExtendedWithProps { + + @PersistenceContext(type = PersistenceContextType.EXTENDED, properties = { @PersistenceProperty(name = "foo", value = "bar") }) + private EntityManager em; + } + + + private interface EntityManagerFactoryWithInfo extends EntityManagerFactory, EntityManagerFactoryInfo { + + } + + + private static class DummyInvocationHandler implements InvocationHandler, Serializable { + + public static boolean closed; + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if ("close".equals(method.getName())) { + closed = true; + return null; + } + if ("toString".equals(method.getName())) { + return ""; + } + throw new IllegalStateException(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/SharedEntityManagerFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/SharedEntityManagerFactoryTests.java new file mode 100644 index 00000000000..70f80e12194 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/support/SharedEntityManagerFactoryTests.java @@ -0,0 +1,89 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa.support; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.orm.jpa.EntityManagerHolder; +import org.springframework.orm.jpa.EntityManagerProxy; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class SharedEntityManagerFactoryTests extends TestCase { + + public void testValidUsage() { + Object o = new Object(); + + MockControl emMc = MockControl.createControl(EntityManager.class); + EntityManager mockEm = (EntityManager) emMc.getMock(); + + mockEm.contains(o); + emMc.setReturnValue(false, 1); + + mockEm.close(); + emMc.setVoidCallable(1); + emMc.replay(); + + MockControl emfMc = MockControl.createControl(EntityManagerFactory.class); + EntityManagerFactory mockEmf = (EntityManagerFactory) emfMc.getMock(); + mockEmf.createEntityManager(); + emfMc.setReturnValue(mockEm, 1); + emfMc.replay(); + + SharedEntityManagerBean proxyFactoryBean = new SharedEntityManagerBean(); + proxyFactoryBean.setEntityManagerFactory(mockEmf); + proxyFactoryBean.afterPropertiesSet(); + + assertTrue(EntityManager.class.isAssignableFrom(proxyFactoryBean.getObjectType())); + assertTrue(proxyFactoryBean.isSingleton()); + + EntityManager proxy = (EntityManager) proxyFactoryBean.getObject(); + assertSame(proxy, proxyFactoryBean.getObject()); + assertFalse(proxy.contains(o)); + + assertTrue(proxy instanceof EntityManagerProxy); + EntityManagerProxy emProxy = (EntityManagerProxy) proxy; + try { + emProxy.getTargetEntityManager(); + fail("Should have thrown IllegalStateException outside of transaction"); + } + catch (IllegalStateException ex) { + // expected + } + + TransactionSynchronizationManager.bindResource(mockEmf, new EntityManagerHolder(mockEm)); + try { + assertSame(mockEm, emProxy.getTargetEntityManager()); + } + finally { + TransactionSynchronizationManager.unbindResource(mockEmf); + } + + emfMc.verify(); + emMc.verify(); + + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/TopLinkEntityManagerFactoryIntegrationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/TopLinkEntityManagerFactoryIntegrationTests.java new file mode 100644 index 00000000000..ef97dec7a98 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/TopLinkEntityManagerFactoryIntegrationTests.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa.toplink; + +import org.springframework.orm.jpa.AbstractContainerEntityManagerFactoryIntegrationTests; +import org.springframework.orm.jpa.EntityManagerFactoryInfo; + +/** + * TopLink-specific JPA tests. + * + * @author Costin Leau + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class TopLinkEntityManagerFactoryIntegrationTests extends AbstractContainerEntityManagerFactoryIntegrationTests { + + protected String[] getConfigLocations() { + return TOPLINK_CONFIG_LOCATIONS; + } + + + public void testCanCastNativeEntityManagerFactoryToTopLinkEntityManagerFactoryImpl() { + EntityManagerFactoryInfo emfi = (EntityManagerFactoryInfo) entityManagerFactory; + assertTrue(emfi.getNativeEntityManagerFactory().getClass().getName().endsWith("EntityManagerFactoryImpl")); + } + + public void testCanCastSharedEntityManagerProxyToTopLinkEntityManager() { + assertTrue(sharedEntityManager instanceof oracle.toplink.essentials.ejb.cmp3.EntityManager); + oracle.toplink.essentials.ejb.cmp3.EntityManager toplinkEntityManager = + (oracle.toplink.essentials.ejb.cmp3.EntityManager) sharedEntityManager; + assertNotNull(toplinkEntityManager.getActiveSession()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/TopLinkMultiEntityManagerFactoryIntegrationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/TopLinkMultiEntityManagerFactoryIntegrationTests.java new file mode 100644 index 00000000000..16b603988b8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/TopLinkMultiEntityManagerFactoryIntegrationTests.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2006 the original author 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.orm.jpa.toplink; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; + +import org.springframework.orm.jpa.AbstractContainerEntityManagerFactoryIntegrationTests; + +/** + * Toplink-specific JPA tests with multiple EntityManagerFactory instances. + * + * @author Costin Leau + */ +public class TopLinkMultiEntityManagerFactoryIntegrationTests extends + AbstractContainerEntityManagerFactoryIntegrationTests { + + private EntityManagerFactory entityManagerFactory2; + + + public TopLinkMultiEntityManagerFactoryIntegrationTests() { + setAutowireMode(AUTOWIRE_BY_NAME); + } + + public void setEntityManagerFactory2(EntityManagerFactory entityManagerFactory2) { + this.entityManagerFactory2 = entityManagerFactory2; + } + + protected String[] getConfigLocations() { + return new String[] { + "/org/springframework/orm/jpa/toplink/toplink-manager-multi.xml", + "/org/springframework/orm/jpa/memdb.xml" + }; + } + + + public void testEntityManagerFactory2() { + EntityManager em = this.entityManagerFactory2.createEntityManager(); + try { + em.createQuery("select tb from TestBean"); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + finally { + em.close(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/toplink-manager-multi.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/toplink-manager-multi.xml new file mode 100644 index 00000000000..a6869f952b5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/toplink-manager-multi.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/toplink-manager.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/toplink-manager.xml new file mode 100644 index 00000000000..a3cbcfc899f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jpa/toplink/toplink-manager.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/remoting/caucho/CauchoRemotingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/remoting/caucho/CauchoRemotingTests.java new file mode 100644 index 00000000000..66016a9fc8b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/remoting/caucho/CauchoRemotingTests.java @@ -0,0 +1,224 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.remoting.caucho; + +import com.caucho.burlap.client.BurlapProxyFactory; +import com.caucho.hessian.client.HessianProxyFactory; +import junit.framework.TestCase; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.remoting.RemoteAccessException; + +/** + * @author Juergen Hoeller + * @since 16.05.2003 + */ +public class CauchoRemotingTests extends TestCase { + + public void testHessianProxyFactoryBeanWithAccessError() throws Exception { + HessianProxyFactoryBean factory = new HessianProxyFactoryBean(); + try { + factory.setServiceInterface(TestBean.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + factory.setServiceInterface(ITestBean.class); + factory.setServiceUrl("http://localhosta/testbean"); + factory.afterPropertiesSet(); + + assertTrue("Correct singleton value", factory.isSingleton()); + assertTrue(factory.getObject() instanceof ITestBean); + ITestBean bean = (ITestBean) factory.getObject(); + + try { + bean.setName("test"); + fail("Should have thrown RemoteAccessException"); + } + catch (RemoteAccessException ex) { + // expected + } + } + + public void testHessianProxyFactoryBeanWithAuthenticationAndAccessError() throws Exception { + HessianProxyFactoryBean factory = new HessianProxyFactoryBean(); + try { + factory.setServiceInterface(TestBean.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + factory.setServiceInterface(ITestBean.class); + factory.setServiceUrl("http://localhosta/testbean"); + factory.setUsername("test"); + factory.setPassword("bean"); + factory.setOverloadEnabled(true); + factory.afterPropertiesSet(); + + assertTrue("Correct singleton value", factory.isSingleton()); + assertTrue(factory.getObject() instanceof ITestBean); + ITestBean bean = (ITestBean) factory.getObject(); + + try { + bean.setName("test"); + fail("Should have thrown RemoteAccessException"); + } + catch (RemoteAccessException ex) { + // expected + } + } + + public void testHessianProxyFactoryBeanWithCustomProxyFactory() throws Exception { + TestHessianProxyFactory proxyFactory = new TestHessianProxyFactory(); + HessianProxyFactoryBean factory = new HessianProxyFactoryBean(); + factory.setServiceInterface(ITestBean.class); + factory.setServiceUrl("http://localhosta/testbean"); + factory.setProxyFactory(proxyFactory); + factory.setUsername("test"); + factory.setPassword("bean"); + factory.setOverloadEnabled(true); + factory.afterPropertiesSet(); + assertTrue("Correct singleton value", factory.isSingleton()); + assertTrue(factory.getObject() instanceof ITestBean); + ITestBean bean = (ITestBean) factory.getObject(); + + assertEquals(proxyFactory.user, "test"); + assertEquals(proxyFactory.password, "bean"); + assertTrue(proxyFactory.overloadEnabled); + + try { + bean.setName("test"); + fail("Should have thrown RemoteAccessException"); + } + catch (RemoteAccessException ex) { + // expected + } + } + + public void testBurlapProxyFactoryBeanWithAccessError() throws Exception { + BurlapProxyFactoryBean factory = new BurlapProxyFactoryBean(); + factory.setServiceInterface(ITestBean.class); + factory.setServiceUrl("http://localhosta/testbean"); + factory.afterPropertiesSet(); + + assertTrue("Correct singleton value", factory.isSingleton()); + assertTrue(factory.getObject() instanceof ITestBean); + ITestBean bean = (ITestBean) factory.getObject(); + + try { + bean.setName("test"); + fail("Should have thrown RemoteAccessException"); + } + catch (RemoteAccessException ex) { + // expected + } + } + + public void testBurlapProxyFactoryBeanWithAuthenticationAndAccessError() throws Exception { + BurlapProxyFactoryBean factory = new BurlapProxyFactoryBean(); + factory.setServiceInterface(ITestBean.class); + factory.setServiceUrl("http://localhosta/testbean"); + factory.setUsername("test"); + factory.setPassword("bean"); + factory.setOverloadEnabled(true); + factory.afterPropertiesSet(); + + assertTrue("Correct singleton value", factory.isSingleton()); + assertTrue(factory.getObject() instanceof ITestBean); + ITestBean bean = (ITestBean) factory.getObject(); + + try { + bean.setName("test"); + fail("Should have thrown RemoteAccessException"); + } + catch (RemoteAccessException ex) { + // expected + } + } + + public void testBurlapProxyFactoryBeanWithCustomProxyFactory() throws Exception { + TestBurlapProxyFactory proxyFactory = new TestBurlapProxyFactory(); + BurlapProxyFactoryBean factory = new BurlapProxyFactoryBean(); + factory.setServiceInterface(ITestBean.class); + factory.setServiceUrl("http://localhosta/testbean"); + factory.setProxyFactory(proxyFactory); + factory.setUsername("test"); + factory.setPassword("bean"); + factory.setOverloadEnabled(true); + factory.afterPropertiesSet(); + + assertTrue("Correct singleton value", factory.isSingleton()); + assertTrue(factory.getObject() instanceof ITestBean); + ITestBean bean = (ITestBean) factory.getObject(); + + assertEquals(proxyFactory.user, "test"); + assertEquals(proxyFactory.password, "bean"); + assertTrue(proxyFactory.overloadEnabled); + + try { + bean.setName("test"); + fail("Should have thrown RemoteAccessException"); + } + catch (RemoteAccessException ex) { + // expected + } + } + + + private static class TestHessianProxyFactory extends HessianProxyFactory { + + private String user; + private String password; + private boolean overloadEnabled; + + public void setUser(String user) { + this.user = user; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setOverloadEnabled(boolean overloadEnabled) { + this.overloadEnabled = overloadEnabled; + } + } + + + private static class TestBurlapProxyFactory extends BurlapProxyFactory { + + private String user; + private String password; + private boolean overloadEnabled; + + public void setUser(String user) { + this.user = user; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setOverloadEnabled(boolean overloadEnabled) { + this.overloadEnabled = overloadEnabled; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/JaxWsSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/JaxWsSupportTests.java new file mode 100644 index 00000000000..a15d7c314f6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/JaxWsSupportTests.java @@ -0,0 +1,144 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.remoting.jaxws; + +import java.net.MalformedURLException; +import java.net.URL; + +import javax.xml.namespace.QName; +import javax.xml.ws.BindingProvider; +import javax.xml.ws.Service; +import javax.xml.ws.WebServiceClient; +import javax.xml.ws.WebServiceRef; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.annotation.AnnotationConfigUtils; +import org.springframework.context.support.GenericApplicationContext; + +/** + * @author Juergen Hoeller + * @since 2.5 + */ +public class JaxWsSupportTests extends TestCase { + + public void testJaxWsPortAccess() throws Exception { + GenericApplicationContext ac = new GenericApplicationContext(); + + GenericBeanDefinition serviceDef = new GenericBeanDefinition(); + serviceDef.setBeanClass(OrderServiceImpl.class); + ac.registerBeanDefinition("service", serviceDef); + + GenericBeanDefinition exporterDef = new GenericBeanDefinition(); + exporterDef.setBeanClass(SimpleJaxWsServiceExporter.class); + exporterDef.getPropertyValues().addPropertyValue("baseAddress", "http://localhost:9999/"); + ac.registerBeanDefinition("exporter", exporterDef); + + GenericBeanDefinition clientDef = new GenericBeanDefinition(); + clientDef.setBeanClass(JaxWsPortProxyFactoryBean.class); + clientDef.getPropertyValues().addPropertyValue("wsdlDocumentUrl", "http://localhost:9999/OrderService?wsdl"); + clientDef.getPropertyValues().addPropertyValue("namespaceUri", "http://jaxws.remoting.springframework.org/"); + clientDef.getPropertyValues().addPropertyValue("username", "juergen"); + clientDef.getPropertyValues().addPropertyValue("password", "hoeller"); + clientDef.getPropertyValues().addPropertyValue("serviceName", "OrderService"); + clientDef.getPropertyValues().addPropertyValue("serviceInterface", OrderService.class); + clientDef.getPropertyValues().addPropertyValue("lookupServiceOnStartup", Boolean.FALSE); + ac.registerBeanDefinition("client", clientDef); + + GenericBeanDefinition serviceFactoryDef = new GenericBeanDefinition(); + serviceFactoryDef.setBeanClass(LocalJaxWsServiceFactoryBean.class); + serviceFactoryDef.getPropertyValues().addPropertyValue("wsdlDocumentUrl", "http://localhost:9999/OrderService?wsdl"); + serviceFactoryDef.getPropertyValues().addPropertyValue("namespaceUri", "http://jaxws.remoting.springframework.org/"); + serviceFactoryDef.getPropertyValues().addPropertyValue("serviceName", "OrderService"); + ac.registerBeanDefinition("orderService", serviceFactoryDef); + + ac.registerBeanDefinition("accessor", new RootBeanDefinition(ServiceAccessor.class)); + AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); + + try { + ac.refresh(); + + OrderService orderService = (OrderService) ac.getBean("client", OrderService.class); + assertTrue(orderService instanceof BindingProvider); + ((BindingProvider) orderService).getRequestContext(); + + String order = orderService.getOrder(1000); + assertEquals("order 1000", order); + try { + orderService.getOrder(0); + fail("Should have thrown OrderNotFoundException"); + } + catch (OrderNotFoundException ex) { + // expected + } + + ServiceAccessor serviceAccessor = (ServiceAccessor) ac.getBean("accessor", ServiceAccessor.class); + order = serviceAccessor.orderService.getOrder(1000); + assertEquals("order 1000", order); + try { + serviceAccessor.orderService.getOrder(0); + fail("Should have thrown OrderNotFoundException"); + } + catch (OrderNotFoundException ex) { + // expected + } + } + catch (BeanCreationException ex) { + if ("exporter".equals(ex.getBeanName()) && ex.getRootCause() instanceof ClassNotFoundException) { + // ignore - probably running on JDK < 1.6 without the JAX-WS impl present + } + else { + throw ex; + } + } + finally { + ac.close(); + } + } + + + public static class ServiceAccessor { + + @WebServiceRef + public OrderService orderService; + + public OrderService myService; + + @WebServiceRef(value=OrderServiceService.class, wsdlLocation = "http://localhost:9999/OrderService?wsdl") + public void setMyService(OrderService myService) { + this.myService = myService; + } + } + + + @WebServiceClient(targetNamespace = "http://jaxws.remoting.springframework.org/", name="OrderService") + public static class OrderServiceService extends Service { + + public OrderServiceService() throws MalformedURLException { + super(new URL("http://localhost:9999/OrderService?wsdl"), + new QName("http://jaxws.remoting.springframework.org/", "OrderService")); + } + + public OrderServiceService(URL wsdlDocumentLocation, QName serviceName) { + super(wsdlDocumentLocation, serviceName); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/OrderNotFoundException.java b/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/OrderNotFoundException.java new file mode 100644 index 00000000000..3a43306153a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/OrderNotFoundException.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.remoting.jaxws; + +import javax.xml.ws.WebFault; + +/** + * @author Juergen Hoeller + */ +@WebFault +public class OrderNotFoundException extends Exception { + + private String faultInfo; + + public OrderNotFoundException(String message) { + super(message); + } + + public OrderNotFoundException(String message, String faultInfo) { + super(message); + this.faultInfo = faultInfo; + } + + public String getFaultInfo() { + return this.faultInfo; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/OrderService.java b/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/OrderService.java new file mode 100644 index 00000000000..d9cbd15e0bf --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/OrderService.java @@ -0,0 +1,31 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.remoting.jaxws; + +import javax.jws.WebService; +import javax.jws.soap.SOAPBinding; + +/** + * @author Juergen Hoeller + */ +@WebService +@SOAPBinding(style = SOAPBinding.Style.RPC) +public interface OrderService { + + String getOrder(int id) throws OrderNotFoundException; + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/OrderServiceImpl.java b/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/OrderServiceImpl.java new file mode 100644 index 00000000000..6c9ba364621 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxws/OrderServiceImpl.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.remoting.jaxws; + +import javax.annotation.Resource; +import javax.jws.WebService; +import javax.xml.ws.WebServiceContext; + +import org.springframework.util.Assert; + +/** + * @author Juergen Hoeller + */ +@WebService(serviceName="OrderService", portName="OrderService", endpointInterface = "org.springframework.remoting.jaxws.OrderService") +public class OrderServiceImpl implements OrderService { + + @Resource + private WebServiceContext webServiceContext; + + public String getOrder(int id) throws OrderNotFoundException { + Assert.notNull(this.webServiceContext, "WebServiceContext has not been injected"); + if (id == 0) { + throw new OrderNotFoundException("Order 0 not found"); + } + return "order " + id; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutorTests.java new file mode 100644 index 00000000000..022a1cd4684 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutorTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.concurrent; + +import junit.framework.TestCase; + +import org.springframework.core.task.NoOpRunnable; + +/** + * @author Rick Evans + */ +public class ConcurrentTaskExecutorTests extends TestCase { + + public void testZeroArgCtorResultsInDefaultTaskExecutorBeingUsed() throws Exception { + ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor(); + // must not throw a NullPointerException + executor.execute(new NoOpRunnable()); + } + + public void testPassingNullExecutorToCtorResultsInDefaultTaskExecutorBeingUsed() throws Exception { + ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor(null); + // must not throw a NullPointerException + executor.execute(new NoOpRunnable()); + } + + public void testPassingNullExecutorToSetterResultsInDefaultTaskExecutorBeingUsed() throws Exception { + ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor(); + executor.setConcurrentExecutor(null); + // must not throw a NullPointerException + executor.execute(new NoOpRunnable()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scheduling/concurrent/ScheduledExecutorFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/concurrent/ScheduledExecutorFactoryBeanTests.java new file mode 100644 index 00000000000..ce3349c10a4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/concurrent/ScheduledExecutorFactoryBeanTests.java @@ -0,0 +1,264 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.concurrent; + +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.core.task.NoOpRunnable; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class ScheduledExecutorFactoryBeanTests extends TestCase { + + public void testThrowsExceptionIfPoolSizeIsLessThanZero() throws Exception { + try { + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); + factory.setPoolSize(-1); + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ + new NoOpScheduledExecutorTask() + }); + factory.afterPropertiesSet(); + fail("Pool size less than zero"); + } + catch (IllegalArgumentException expected) { + } + } + + public void testShutdownNowIsPropagatedToTheExecutorOnDestroy() throws Exception { + MockControl mockScheduledExecutorService = MockControl.createNiceControl(ScheduledExecutorService.class); + final ScheduledExecutorService executor = (ScheduledExecutorService) mockScheduledExecutorService.getMock(); + executor.shutdownNow(); + mockScheduledExecutorService.setReturnValue(null); + mockScheduledExecutorService.replay(); + + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() { + protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { + return executor; + } + }; + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ + new NoOpScheduledExecutorTask() + }); + factory.afterPropertiesSet(); + factory.destroy(); + + mockScheduledExecutorService.verify(); + } + + public void testShutdownIsPropagatedToTheExecutorOnDestroy() throws Exception { + MockControl mockScheduledExecutorService = MockControl.createNiceControl(ScheduledExecutorService.class); + final ScheduledExecutorService executor = (ScheduledExecutorService) mockScheduledExecutorService.getMock(); + executor.shutdown(); + mockScheduledExecutorService.setVoidCallable(); + mockScheduledExecutorService.replay(); + + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() { + protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { + return executor; + } + }; + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ + new NoOpScheduledExecutorTask() + }); + factory.setWaitForTasksToCompleteOnShutdown(true); + factory.afterPropertiesSet(); + factory.destroy(); + + mockScheduledExecutorService.verify(); + } + + public void testOneTimeExecutionIsSetUpAndFiresCorrectly() throws Exception { + MockControl mockRunnable = MockControl.createControl(Runnable.class); + Runnable runnable = (Runnable) mockRunnable.getMock(); + runnable.run(); + mockRunnable.setVoidCallable(); + mockRunnable.replay(); + + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ + new ScheduledExecutorTask(runnable) + }); + factory.afterPropertiesSet(); + pauseToLetTaskStart(1); + factory.destroy(); + + mockRunnable.verify(); + } + + public void testFixedRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception { + MockControl mockRunnable = MockControl.createControl(Runnable.class); + Runnable runnable = (Runnable) mockRunnable.getMock(); + runnable.run(); + mockRunnable.setVoidCallable(); + runnable.run(); + mockRunnable.setVoidCallable(); + mockRunnable.replay(); + + ScheduledExecutorTask task = new ScheduledExecutorTask(runnable); + task.setPeriod(500); + task.setFixedRate(true); + + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{task}); + factory.afterPropertiesSet(); + pauseToLetTaskStart(2); + factory.destroy(); + + mockRunnable.verify(); + } + + public void testFixedRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception { + MockControl mockRunnable = MockControl.createControl(Runnable.class); + Runnable runnable = (Runnable) mockRunnable.getMock(); + runnable.run(); + mockRunnable.setThrowable(new IllegalStateException()); + runnable.run(); + mockRunnable.setThrowable(new IllegalStateException()); + mockRunnable.replay(); + + ScheduledExecutorTask task = new ScheduledExecutorTask(runnable); + task.setPeriod(500); + task.setFixedRate(true); + + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{task}); + factory.setContinueScheduledExecutionAfterException(true); + factory.afterPropertiesSet(); + pauseToLetTaskStart(2); + factory.destroy(); + + mockRunnable.verify(); + } + + public void testWithInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception { + MockControl mockRunnable = MockControl.createControl(Runnable.class); + Runnable runnable = (Runnable) mockRunnable.getMock(); + runnable.run(); + mockRunnable.setVoidCallable(); + runnable.run(); + mockRunnable.setVoidCallable(); + mockRunnable.replay(); + + ScheduledExecutorTask task = new ScheduledExecutorTask(runnable); + task.setPeriod(500); + task.setDelay(3000); // nice long wait... + + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[] {task}); + factory.afterPropertiesSet(); + pauseToLetTaskStart(1); + // invoke destroy before tasks have even been scheduled... + factory.destroy(); + + try { + mockRunnable.verify(); + fail("Mock must never have been called"); + } + catch (AssertionFailedError expected) { + } + } + + public void testWithInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception { + MockControl mockRunnable = MockControl.createControl(Runnable.class); + Runnable runnable = (Runnable) mockRunnable.getMock(); + runnable.run(); + mockRunnable.setThrowable(new IllegalStateException()); + runnable.run(); + mockRunnable.setThrowable(new IllegalStateException()); + mockRunnable.replay(); + + ScheduledExecutorTask task = new ScheduledExecutorTask(runnable); + task.setPeriod(500); + task.setDelay(3000); // nice long wait... + + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[] {task}); + factory.setContinueScheduledExecutionAfterException(true); + factory.afterPropertiesSet(); + pauseToLetTaskStart(1); + // invoke destroy before tasks have even been scheduled... + factory.destroy(); + + try { + mockRunnable.verify(); + fail("Mock must never have been called"); + } + catch (AssertionFailedError expected) { + } + } + + public void testSettingThreadFactoryToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception { + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() { + protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { + assertNotNull("Bah; the setThreadFactory(..) method must use a default ThreadFactory if a null arg is passed in."); + return super.createExecutor(poolSize, threadFactory, rejectedExecutionHandler); + } + }; + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ + new NoOpScheduledExecutorTask() + }); + factory.setThreadFactory(null); // the null must not propagate + factory.afterPropertiesSet(); + factory.destroy(); + } + + public void testSettingRejectedExecutionHandlerToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception { + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() { + protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { + assertNotNull("Bah; the setRejectedExecutionHandler(..) method must use a default RejectedExecutionHandler if a null arg is passed in."); + return super.createExecutor(poolSize, threadFactory, rejectedExecutionHandler); + } + }; + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ + new NoOpScheduledExecutorTask() + }); + factory.setRejectedExecutionHandler(null); // the null must not propagate + factory.afterPropertiesSet(); + factory.destroy(); + } + + public void testObjectTypeReportsCorrectType() throws Exception { + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); + assertEquals(ScheduledExecutorService.class, factory.getObjectType()); + } + + + private static void pauseToLetTaskStart(int seconds) { + try { + Thread.sleep(seconds * 1000); + } + catch (InterruptedException ignored) { + } + } + + + private static class NoOpScheduledExecutorTask extends ScheduledExecutorTask { + + public NoOpScheduledExecutorTask() { + super(new NoOpRunnable()); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/JRubyScriptFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/JRubyScriptFactoryTests.java index 08bf6b6cc57..63de6c42074 100644 --- a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/JRubyScriptFactoryTests.java +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/JRubyScriptFactoryTests.java @@ -19,6 +19,7 @@ package org.springframework.scripting.jruby; import java.util.Map; import junit.framework.TestCase; +import junit.framework.Assert; import org.springframework.aop.support.AopUtils; import org.springframework.aop.target.dynamic.Refreshable; @@ -54,14 +55,14 @@ public class JRubyScriptFactoryTests extends TestCase { assertFalse("Scripted object should not be instance of Refreshable", calc instanceof Refreshable); assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable); - assertEquals(calc, calc); - assertEquals(messenger, messenger); + Assert.assertEquals(calc, calc); + Assert.assertEquals(messenger, messenger); assertTrue(!messenger.equals(calc)); - assertTrue(messenger.hashCode() != calc.hashCode()); + assertNotSame(messenger.hashCode(), calc.hashCode()); assertTrue(!messenger.toString().equals(calc.toString())); String desiredMessage = "Hello World!"; - assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); + Assert.assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); } public void testNonStaticScript() throws Exception { @@ -72,12 +73,12 @@ public class JRubyScriptFactoryTests extends TestCase { assertTrue("Should be an instance of Refreshable", messenger instanceof Refreshable); String desiredMessage = "Hello World!"; - assertEquals("Message is incorrect.", desiredMessage, messenger.getMessage()); + Assert.assertEquals("Message is incorrect.", desiredMessage, messenger.getMessage()); Refreshable refreshable = (Refreshable) messenger; refreshable.refresh(); - assertEquals("Message is incorrect after refresh.", desiredMessage, messenger.getMessage()); + Assert.assertEquals("Message is incorrect after refresh.", desiredMessage, messenger.getMessage()); assertEquals("Incorrect refresh count", 2, refreshable.getRefreshCount()); } @@ -141,14 +142,14 @@ public class JRubyScriptFactoryTests extends TestCase { TestBean testBean = (TestBean) ctx.getBean("testBean"); Messenger messenger = (Messenger) ctx.getBean("messenger"); - assertEquals("Hello World!", messenger.getMessage()); + Assert.assertEquals("Hello World!", messenger.getMessage()); assertFalse(messenger instanceof Refreshable); TestBeanAwareMessenger messengerByType = (TestBeanAwareMessenger) ctx.getBean("messengerByType"); - assertEquals(testBean, messengerByType.getTestBean()); + Assert.assertEquals(testBean, messengerByType.getTestBean()); TestBeanAwareMessenger messengerByName = (TestBeanAwareMessenger) ctx.getBean("messengerByName"); - assertEquals(testBean, messengerByName.getTestBean()); + Assert.assertEquals(testBean, messengerByName.getTestBean()); } public void testPrototypeScriptFromTag() throws Exception { @@ -158,12 +159,12 @@ public class JRubyScriptFactoryTests extends TestCase { assertNotSame(messenger, messenger2); assertSame(messenger.getClass(), messenger2.getClass()); - assertEquals("Hello World!", messenger.getMessage()); - assertEquals("Hello World!", messenger2.getMessage()); + Assert.assertEquals("Hello World!", messenger.getMessage()); + Assert.assertEquals("Hello World!", messenger2.getMessage()); messenger.setMessage("Bye World!"); messenger2.setMessage("Byebye World!"); - assertEquals("Bye World!", messenger.getMessage()); - assertEquals("Byebye World!", messenger2.getMessage()); + Assert.assertEquals("Bye World!", messenger.getMessage()); + Assert.assertEquals("Byebye World!", messenger2.getMessage()); } public void testInlineScriptFromTag() throws Exception { @@ -176,18 +177,18 @@ public class JRubyScriptFactoryTests extends TestCase { public void testRefreshableFromTag() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd.xml", getClass()); Messenger messenger = (Messenger) ctx.getBean("refreshableMessenger"); - assertEquals("Hello World!", messenger.getMessage()); + Assert.assertEquals("Hello World!", messenger.getMessage()); assertTrue("Messenger should be Refreshable", messenger instanceof Refreshable); } public void testThatMultipleScriptInterfacesAreSupported() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd.xml", getClass()); Messenger messenger = (Messenger) ctx.getBean("calculatingMessenger"); - assertEquals("Hello World!", messenger.getMessage()); + Assert.assertEquals("Hello World!", messenger.getMessage()); // cool, now check that the Calculator interface is also exposed Calculator calc = (Calculator) messenger; - assertEquals(0, calc.add(2, -2)); + Assert.assertEquals(0, calc.add(2, -2)); } public void testWithComplexArg() throws Exception { @@ -269,7 +270,7 @@ public class JRubyScriptFactoryTests extends TestCase { public void testAOP() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-aop.xml", getClass()); Messenger messenger = (Messenger) ctx.getBean("messenger"); - assertEquals(new StringBuffer("Hello World!").reverse().toString(), messenger.getMessage()); + Assert.assertEquals(new StringBuffer("Hello World!").reverse().toString(), messenger.getMessage()); } diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/annotation/ProfileValueAnnotationAwareTransactionalTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/annotation/ProfileValueAnnotationAwareTransactionalTests-context.xml new file mode 100644 index 00000000000..3c4fc976b8e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/annotation/ProfileValueAnnotationAwareTransactionalTests-context.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/annotation/ProfileValueAnnotationAwareTransactionalTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/annotation/ProfileValueAnnotationAwareTransactionalTests.java new file mode 100644 index 00000000000..e92bfe3353a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/annotation/ProfileValueAnnotationAwareTransactionalTests.java @@ -0,0 +1,146 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.annotation; + +import junit.framework.TestCase; +import junit.framework.TestResult; + +/** + * Verifies proper handling of {@link IfProfileValue @IfProfileValue} and + * {@link ProfileValueSourceConfiguration @ProfileValueSourceConfiguration} in + * conjunction with {@link AbstractAnnotationAwareTransactionalTests}. + * + * @author Sam Brannen + * @since 2.5 + */ +public class ProfileValueAnnotationAwareTransactionalTests extends TestCase { + + private static final String NAME = "ProfileValueAnnotationAwareTransactionalTests.profile_value.name"; + + private static final String VALUE = "enigma"; + + + public ProfileValueAnnotationAwareTransactionalTests() { + System.setProperty(NAME, VALUE); + } + + private void runTestAndAssertCounters(Class testCaseType, + String testName, int expectedInvocationCount, int expectedErrorCount, int expectedFailureCount) + throws Exception { + + DefaultProfileValueSourceTestCase testCase = testCaseType.newInstance(); + testCase.setName(testName); + TestResult testResult = testCase.run(); + assertEquals("Verifying number of invocations for test method [" + testName + "].", expectedInvocationCount, + testCase.invocationCount); + assertEquals("Verifying number of errors for test method [" + testName + "].", expectedErrorCount, + testResult.errorCount()); + assertEquals("Verifying number of failures for test method [" + testName + "].", expectedFailureCount, + testResult.failureCount()); + } + + private void runTests(Class testCaseType) throws Exception { + runTestAndAssertCounters(testCaseType, "testIfProfileValueEmpty", 0, 0, 0); + runTestAndAssertCounters(testCaseType, "testIfProfileValueDisabledViaWrongName", 0, 0, 0); + runTestAndAssertCounters(testCaseType, "testIfProfileValueDisabledViaWrongValue", 0, 0, 0); + runTestAndAssertCounters(testCaseType, "testIfProfileValueEnabledViaSingleValue", 1, 0, 0); + runTestAndAssertCounters(testCaseType, "testIfProfileValueEnabledViaMultipleValues", 1, 0, 0); + runTestAndAssertCounters(testCaseType, "testIfProfileValueNotConfigured", 1, 0, 0); + } + + public void testDefaultProfileValueSource() throws Exception { + assertEquals("Verifying the type of the configured ProfileValueSource.", SystemProfileValueSource.class, + new DefaultProfileValueSourceTestCase().getProfileValueSource().getClass()); + runTests(DefaultProfileValueSourceTestCase.class); + } + + public void testHardCodedProfileValueSource() throws Exception { + assertEquals("Verifying the type of the configured ProfileValueSource.", HardCodedProfileValueSource.class, + new HardCodedProfileValueSourceTestCase().getProfileValueSource().getClass()); + runTests(HardCodedProfileValueSourceTestCase.class); + } + + + protected static class DefaultProfileValueSourceTestCase extends AbstractAnnotationAwareTransactionalTests { + + int invocationCount = 0; + + public DefaultProfileValueSourceTestCase() { + } + + public ProfileValueSource getProfileValueSource() { + return super.profileValueSource; + } + + @Override + protected String getConfigPath() { + return "ProfileValueAnnotationAwareTransactionalTests-context.xml"; + } + + @NotTransactional + @IfProfileValue(name = NAME) + public void testIfProfileValueEmpty() { + this.invocationCount++; + fail("The body of a disabled test should never be executed!"); + } + + @NotTransactional + @IfProfileValue(name = NAME + "X", value = VALUE) + public void testIfProfileValueDisabledViaWrongName() { + this.invocationCount++; + fail("The body of a disabled test should never be executed!"); + } + + @NotTransactional + @IfProfileValue(name = NAME, value = VALUE + "X") + public void testIfProfileValueDisabledViaWrongValue() { + this.invocationCount++; + fail("The body of a disabled test should never be executed!"); + } + + @NotTransactional + @IfProfileValue(name = NAME, value = VALUE) + public void testIfProfileValueEnabledViaSingleValue() { + this.invocationCount++; + } + + @NotTransactional + @IfProfileValue(name = NAME, values = { "foo", VALUE, "bar" }) + public void testIfProfileValueEnabledViaMultipleValues() { + this.invocationCount++; + } + + @NotTransactional + public void testIfProfileValueNotConfigured() { + this.invocationCount++; + } + } + + + @ProfileValueSourceConfiguration(HardCodedProfileValueSource.class) + protected static class HardCodedProfileValueSourceTestCase extends DefaultProfileValueSourceTestCase { + } + + + public static class HardCodedProfileValueSource implements ProfileValueSource { + + public String get(String key) { + return (key.equals(NAME) ? VALUE : null); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/SpringRunnerContextCacheTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/SpringRunnerContextCacheTests.java new file mode 100644 index 00000000000..e2536d319b6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/SpringRunnerContextCacheTests.java @@ -0,0 +1,118 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * JUnit 4 based unit test which verifies correct + * {@link ContextCache application context caching} in conjunction with the + * {@link SpringJUnit4ClassRunner} and the {@link DirtiesContext} annotation. + * + * @author Sam Brannen + * @author Juergen Hoeller + * @since 2.5 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = "/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests-context.xml") +public class SpringRunnerContextCacheTests implements ApplicationContextAware { + + private static ApplicationContext dirtiedApplicationContext; + + protected ApplicationContext applicationContext; + + + /** + * Asserts the statistics of the supplied context cache. + * @param usageScenario the scenario in which the statistics are used + * @param expectedSize the expected number of contexts in the cache + * @param expectedHitCount the expected hit count + * @param expectedMissCount the expected miss count + */ + public static final void assertContextCacheStatistics(String usageScenario, int expectedSize, + int expectedHitCount, int expectedMissCount) { + + ContextCache contextCache = TestContextManager.contextCache; + assertEquals("Verifying number of contexts in cache (" + usageScenario + ").", expectedSize, + contextCache.size()); + assertEquals("Verifying number of cache hits (" + usageScenario + ").", expectedHitCount, + contextCache.getHitCount()); + assertEquals("Verifying number of cache misses (" + usageScenario + ").", expectedMissCount, + contextCache.getMissCount()); + } + + @BeforeClass + public static void verifyInitialCacheState() { + dirtiedApplicationContext = null; + ContextCache contextCache = TestContextManager.contextCache; + contextCache.clear(); + contextCache.clearStatistics(); + assertContextCacheStatistics("BeforeClass", 0, 0, 0); + } + + @AfterClass + public static void verifyFinalCacheState() { + assertContextCacheStatistics("AfterClass", 1, 1, 2); + } + + + public final void setApplicationContext(final ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Test + @DirtiesContext + public void dirtyContext() { + assertContextCacheStatistics("dirtyContext()", 1, 0, 1); + assertNotNull("The application context should have been set due to ApplicationContextAware semantics.", + this.applicationContext); + SpringRunnerContextCacheTests.dirtiedApplicationContext = this.applicationContext; + } + + @Test + public void verifyContextWasDirtied() { + assertContextCacheStatistics("verifyContextWasDirtied()", 1, 0, 2); + assertNotNull("The application context should have been set due to ApplicationContextAware semantics.", + this.applicationContext); + assertNotSame("The application context should have been 'dirtied'.", + SpringRunnerContextCacheTests.dirtiedApplicationContext, this.applicationContext); + SpringRunnerContextCacheTests.dirtiedApplicationContext = this.applicationContext; + } + + @Test + public void verifyContextWasNotDirtied() { + assertContextCacheStatistics("verifyContextWasNotDirtied()", 1, 1, 2); + assertNotNull("The application context should have been set due to ApplicationContextAware semantics.", + this.applicationContext); + assertSame("The application context should NOT have been 'dirtied'.", + SpringRunnerContextCacheTests.dirtiedApplicationContext, this.applicationContext); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/TestContextManagerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/TestContextManagerTests.java new file mode 100644 index 00000000000..520485e33ff --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/TestContextManagerTests.java @@ -0,0 +1,177 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import org.springframework.test.context.support.AbstractTestExecutionListener; + +/** + * JUnit 4 based unit test for {@link TestContextManager}, which verifies + * proper execution order of registered + * {@link TestExecutionListener TestExecutionListeners}. + * + * @author Sam Brannen + * @since 2.5 + */ +public class TestContextManagerTests { + + private static final String FIRST = "veni"; + private static final String SECOND = "vidi"; + private static final String THIRD = "vici"; + + private static final List afterTestMethodCalls = new ArrayList(); + private static final List beforeTestMethodCalls = new ArrayList(); + + protected static final Log logger = LogFactory.getLog(TestContextManagerTests.class); + + private TestContextManager testContextManager = null; + + + /** + * Asserts the execution order of 'before' and 'after' test + * method calls on {@link TestExecutionListener listeners} registered for + * the configured {@link TestContextManager}. + * + * @see #beforeTestMethodCalls + * @see #afterTestMethodCalls + */ + private static void assertExecutionOrder(List expectedBeforeTestMethodCalls, + List expectedAfterTestMethodCalls, final String usageContext) { + + if (expectedBeforeTestMethodCalls == null) { + expectedBeforeTestMethodCalls = new ArrayList(); + } + if (expectedAfterTestMethodCalls == null) { + expectedAfterTestMethodCalls = new ArrayList(); + } + + if (logger.isDebugEnabled()) { + for (final String listenerName : beforeTestMethodCalls) { + logger.debug("'before' listener [" + listenerName + "] (" + usageContext + ")."); + } + for (final String listenerName : afterTestMethodCalls) { + logger.debug("'after' listener [" + listenerName + "] (" + usageContext + ")."); + } + } + + assertTrue("Verifying execution order of 'before' listeners' (" + usageContext + ").", + CollectionUtils.isEqualCollection(expectedBeforeTestMethodCalls, beforeTestMethodCalls)); + assertTrue("Verifying execution order of 'after' listeners' (" + usageContext + ").", + CollectionUtils.isEqualCollection(expectedAfterTestMethodCalls, afterTestMethodCalls)); + } + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + beforeTestMethodCalls.clear(); + afterTestMethodCalls.clear(); + assertExecutionOrder(null, null, "BeforeClass"); + } + + /** + * Verifies the expected {@link TestExecutionListener} + * execution order after all test methods have completed. + */ + @AfterClass + public static void verifyListenerExecutionOrderAfterClass() throws Exception { + assertExecutionOrder(Arrays. asList(FIRST, SECOND, THIRD), + Arrays. asList(THIRD, SECOND, FIRST), "AfterClass"); + } + + @Before + public void setUpTestContextManager() throws Throwable { + + final Method testMethod = ExampleTest.class.getDeclaredMethod("exampleTestMethod", (Class[]) null); + this.testContextManager = new TestContextManager(ExampleTest.class); + this.testContextManager.registerTestExecutionListeners(new NamedTestExecutionListener(FIRST), + new NamedTestExecutionListener(SECOND), new NamedTestExecutionListener(THIRD)); + + assertEquals("Verifying the number of registered TestExecutionListeners.", 6, + this.testContextManager.getTestExecutionListeners().size()); + + this.testContextManager.beforeTestMethod(new ExampleTest(), testMethod); + } + + /** + * Verifies the expected {@link TestExecutionListener} + * execution order within a test method. + * + * @see #verifyListenerExecutionOrderAfterClass() + */ + @Test + public void verifyListenerExecutionOrderWithinTestMethod() { + assertExecutionOrder(Arrays. asList(FIRST, SECOND, THIRD), null, "Test"); + } + + @After + public void tearDownTestContextManager() throws Throwable { + final Method testMethod = ExampleTest.class.getDeclaredMethod("exampleTestMethod", (Class[]) null); + this.testContextManager.afterTestMethod(new ExampleTest(), testMethod, null); + this.testContextManager = null; + } + + + @ContextConfiguration + private static class ExampleTest { + + public void exampleTestMethod() { + assertTrue(true); + } + } + + private static class NamedTestExecutionListener extends AbstractTestExecutionListener { + + private final String name; + + + public NamedTestExecutionListener(final String name) { + this.name = name; + } + + @Override + public void afterTestMethod(final TestContext testContext) { + afterTestMethodCalls.add(this.name); + } + + @Override + public void beforeTestMethod(final TestContext testContext) { + beforeTestMethodCalls.add(this.name); + } + + @Override + public String toString() { + return new ToStringBuilder(this).append("name", this.name).toString(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/TestExecutionListenersTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/TestExecutionListenersTests.java new file mode 100644 index 00000000000..aca8aff3cda --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/TestExecutionListenersTests.java @@ -0,0 +1,145 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import org.springframework.test.context.support.AbstractTestExecutionListener; + +/** + *

+ * JUnit 4 based unit test for the + * {@link TestExecutionListeners @TestExecutionListeners} annotation, which + * verifies: + *

+ *
    + *
  • Proper registering of {@link TestExecutionListener listeners} in + * conjunction with a {@link TestContextManager}
  • + *
  • Inherited functionality proposed in SPR-3896
  • + *
+ * + * @author Sam Brannen + * @since 2.5 + */ +public class TestExecutionListenersTests { + + @Test + public void verifyNumDefaultListenersRegistered() throws Exception { + TestContextManager testContextManager = new TestContextManager(DefaultListenersExampleTest.class); + assertEquals("Verifying the number of registered TestExecutionListeners for DefaultListenersExampleTest.", 3, + testContextManager.getTestExecutionListeners().size()); + } + + @Test + public void verifyNumNonInheritedDefaultListenersRegistered() throws Exception { + TestContextManager testContextManager = new TestContextManager(NonInheritedDefaultListenersExampleTest.class); + assertEquals( + "Verifying the number of registered TestExecutionListeners for NonInheritedDefaultListenersExampleTest.", + 1, testContextManager.getTestExecutionListeners().size()); + } + + @Test + public void verifyNumInheritedDefaultListenersRegistered() throws Exception { + TestContextManager testContextManager = new TestContextManager(InheritedDefaultListenersExampleTest.class); + assertEquals( + "Verifying the number of registered TestExecutionListeners for InheritedDefaultListenersExampleTest.", + 1, testContextManager.getTestExecutionListeners().size()); + + testContextManager = new TestContextManager(SubInheritedDefaultListenersExampleTest.class); + assertEquals( + "Verifying the number of registered TestExecutionListeners for SubInheritedDefaultListenersExampleTest.", + 1, testContextManager.getTestExecutionListeners().size()); + + testContextManager = new TestContextManager(SubSubInheritedDefaultListenersExampleTest.class); + assertEquals( + "Verifying the number of registered TestExecutionListeners for SubSubInheritedDefaultListenersExampleTest.", + 2, testContextManager.getTestExecutionListeners().size()); + } + + @Test + public void verifyNumListenersRegistered() throws Exception { + TestContextManager testContextManager = new TestContextManager(ExampleTest.class); + assertEquals("Verifying the number of registered TestExecutionListeners for ExampleTest.", 3, + testContextManager.getTestExecutionListeners().size()); + } + + @Test + public void verifyNumNonInheritedListenersRegistered() throws Exception { + TestContextManager testContextManager = new TestContextManager(NonInheritedListenersExampleTest.class); + assertEquals("Verifying the number of registered TestExecutionListeners for NonInheritedListenersExampleTest.", + 1, testContextManager.getTestExecutionListeners().size()); + } + + @Test + public void verifyNumInheritedListenersRegistered() throws Exception { + TestContextManager testContextManager = new TestContextManager(InheritedListenersExampleTest.class); + assertEquals("Verifying the number of registered TestExecutionListeners for InheritedListenersExampleTest.", 4, + testContextManager.getTestExecutionListeners().size()); + } + + + static class DefaultListenersExampleTest { + } + + @TestExecutionListeners( { QuuxTestExecutionListener.class }) + static class InheritedDefaultListenersExampleTest extends DefaultListenersExampleTest { + } + + static class SubInheritedDefaultListenersExampleTest extends InheritedDefaultListenersExampleTest { + } + + @TestExecutionListeners( { EnigmaTestExecutionListener.class }) + static class SubSubInheritedDefaultListenersExampleTest extends SubInheritedDefaultListenersExampleTest { + } + + @TestExecutionListeners(value = { QuuxTestExecutionListener.class }, inheritListeners = false) + static class NonInheritedDefaultListenersExampleTest extends InheritedDefaultListenersExampleTest { + } + + @TestExecutionListeners( { FooTestExecutionListener.class, BarTestExecutionListener.class, + BazTestExecutionListener.class }) + static class ExampleTest { + } + + @TestExecutionListeners( { QuuxTestExecutionListener.class }) + static class InheritedListenersExampleTest extends ExampleTest { + } + + @TestExecutionListeners(value = { QuuxTestExecutionListener.class }, inheritListeners = false) + static class NonInheritedListenersExampleTest extends InheritedListenersExampleTest { + } + + static class FooTestExecutionListener extends AbstractTestExecutionListener { + } + + static class BarTestExecutionListener extends AbstractTestExecutionListener { + } + + static class BazTestExecutionListener extends AbstractTestExecutionListener { + } + + static class QuuxTestExecutionListener extends AbstractTestExecutionListener { + } + + static class EnigmaTestExecutionListener extends AbstractTestExecutionListener { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/ConcreteTransactionalJUnit38SpringContextTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/ConcreteTransactionalJUnit38SpringContextTests-context.xml new file mode 100644 index 00000000000..acdab7073c1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/ConcreteTransactionalJUnit38SpringContextTests-context.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/ConcreteTransactionalJUnit38SpringContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/ConcreteTransactionalJUnit38SpringContextTests.java new file mode 100644 index 00000000000..aeb961df317 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/ConcreteTransactionalJUnit38SpringContextTests.java @@ -0,0 +1,229 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit38; + +import java.util.ArrayList; + +import javax.annotation.Resource; +import javax.sql.DataSource; + +import org.junit.internal.runners.JUnit38ClassRunner; +import org.junit.runner.RunWith; + +import org.springframework.beans.Employee; +import org.springframework.beans.Pet; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.BadSqlGrammarException; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.test.annotation.ExpectedException; +import org.springframework.test.annotation.NotTransactional; +import org.springframework.test.annotation.Timed; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.transaction.AfterTransaction; +import org.springframework.test.context.transaction.BeforeTransaction; +import org.springframework.test.jdbc.SimpleJdbcTestUtils; + +/** + * Combined unit test for {@link AbstractJUnit38SpringContextTests} and + * {@link AbstractTransactionalJUnit38SpringContextTests}. + * + * @author Sam Brannen + * @since 2.5 + */ +@RunWith(JUnit38ClassRunner.class) +@ContextConfiguration +public class ConcreteTransactionalJUnit38SpringContextTests extends AbstractTransactionalJUnit38SpringContextTests + implements BeanNameAware, InitializingBean { + + protected static final String BOB = "bob"; + protected static final String JANE = "jane"; + protected static final String SUE = "sue"; + protected static final String YODA = "yoda"; + + private boolean beanInitialized = false; + + private String beanName = "replace me with [" + getClass().getName() + "]"; + + private Employee employee; + + @Autowired + private Pet pet; + + @Autowired(required = false) + protected Long nonrequiredLong; + + @Resource() + protected String foo; + + protected String bar; + + private boolean inTransaction = false; + + + public ConcreteTransactionalJUnit38SpringContextTests() throws Exception { + this(null); + } + + public ConcreteTransactionalJUnit38SpringContextTests(final String name) throws Exception { + super(name); + } + + protected static int clearPersonTable(final SimpleJdbcTemplate simpleJdbcTemplate) { + return SimpleJdbcTestUtils.deleteFromTables(simpleJdbcTemplate, "person"); + } + + protected static void createPersonTable(final SimpleJdbcTemplate simpleJdbcTemplate) { + try { + simpleJdbcTemplate.update("CREATE TABLE person (name VARCHAR(20) NOT NULL, PRIMARY KEY(name))"); + } + catch (final BadSqlGrammarException bsge) { + /* ignore */ + } + } + + protected static int countRowsInPersonTable(final SimpleJdbcTemplate simpleJdbcTemplate) { + return SimpleJdbcTestUtils.countRowsInTable(simpleJdbcTemplate, "person"); + } + + protected static int addPerson(final SimpleJdbcTemplate simpleJdbcTemplate, final String name) { + return simpleJdbcTemplate.update("INSERT INTO person VALUES(?)", name); + } + + protected static int deletePerson(final SimpleJdbcTemplate simpleJdbcTemplate, final String name) { + return simpleJdbcTemplate.update("DELETE FROM person WHERE name=?", name); + } + + public final void afterPropertiesSet() throws Exception { + this.beanInitialized = true; + } + + public final void setBeanName(final String beanName) { + this.beanName = beanName; + } + + @Autowired + protected final void setEmployee(final Employee employee) { + this.employee = employee; + } + + @Resource + protected final void setBar(final String bar) { + this.bar = bar; + } + + @NotTransactional + @Timed(millis = 10000) + public void testNoOpShouldNotTimeOut() throws Exception { + /* no-op */ + } + + @NotTransactional + @ExpectedException(IndexOutOfBoundsException.class) + public void testExpectedExceptionAnnotation() { + new ArrayList().get(1); + } + + @NotTransactional + public void testApplicationContextSet() { + assertNotNull("The application context should have been set due to ApplicationContextAware semantics.", + super.applicationContext); + } + + @NotTransactional + public void testBeanInitialized() { + assertTrue("This test bean should have been initialized due to InitializingBean semantics.", + this.beanInitialized); + } + + @NotTransactional + public void testBeanNameSet() { + assertEquals("The bean name of this test instance should have been set to the fully qualified class name " + + "due to BeanNameAware semantics.", getClass().getName(), this.beanName); + } + + @NotTransactional + public void testAnnotationAutowiredFields() { + assertNull("The nonrequiredLong property should NOT have been autowired.", this.nonrequiredLong); + assertNotNull("The pet field should have been autowired.", this.pet); + assertEquals("Fido", this.pet.getName()); + } + + @NotTransactional + public void testAnnotationAutowiredMethods() { + assertNotNull("The employee setter method should have been autowired.", this.employee); + assertEquals("John Smith", this.employee.getName()); + } + + @NotTransactional + public void testResourceAnnotationWiredFields() { + assertEquals("The foo field should have been wired via @Resource.", "Foo", this.foo); + } + + @NotTransactional + public void testResourceAnnotationWiredMethods() { + assertEquals("The bar method should have been wired via @Resource.", "Bar", this.bar); + } + + @BeforeTransaction + public void beforeTransaction() { + this.inTransaction = true; + assertEquals("Verifying the number of rows in the person table before a transactional test method.", 1, + countRowsInPersonTable(super.simpleJdbcTemplate)); + assertEquals("Adding yoda", 1, addPerson(super.simpleJdbcTemplate, YODA)); + } + + @Override + public void setUp() throws Exception { + assertEquals("Verifying the number of rows in the person table before a test method.", (this.inTransaction ? 2 + : 1), countRowsInPersonTable(super.simpleJdbcTemplate)); + } + + public void testModifyTestDataWithinTransaction() { + assertEquals("Adding jane", 1, addPerson(super.simpleJdbcTemplate, JANE)); + assertEquals("Adding sue", 1, addPerson(super.simpleJdbcTemplate, SUE)); + assertEquals("Verifying the number of rows in the person table within transactionalMethod2().", 4, + countRowsInPersonTable(super.simpleJdbcTemplate)); + } + + @Override + public void tearDown() throws Exception { + assertEquals("Verifying the number of rows in the person table after a test method.", (this.inTransaction ? 4 + : 1), countRowsInPersonTable(super.simpleJdbcTemplate)); + } + + @AfterTransaction + public void afterTransaction() { + assertEquals("Deleting yoda", 1, deletePerson(super.simpleJdbcTemplate, YODA)); + assertEquals("Verifying the number of rows in the person table after a transactional test method.", 1, + countRowsInPersonTable(super.simpleJdbcTemplate)); + } + + + public static class DatabaseSetup { + + @Autowired + void setDataSource(final DataSource dataSource) { + final SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); + createPersonTable(simpleJdbcTemplate); + clearPersonTable(simpleJdbcTemplate); + addPerson(simpleJdbcTemplate, BOB); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/FailingBeforeAndAfterMethodsTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/FailingBeforeAndAfterMethodsTests-context.xml new file mode 100644 index 00000000000..3c4fc976b8e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/FailingBeforeAndAfterMethodsTests-context.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/FailingBeforeAndAfterMethodsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/FailingBeforeAndAfterMethodsTests.java new file mode 100644 index 00000000000..4e298bc8d0c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/FailingBeforeAndAfterMethodsTests.java @@ -0,0 +1,150 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit38; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.Collection; + +import junit.framework.TestCase; +import junit.framework.TestResult; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestContext; +import org.springframework.test.context.TestExecutionListener; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.support.AbstractTestExecutionListener; +import org.springframework.test.context.transaction.AfterTransaction; +import org.springframework.test.context.transaction.BeforeTransaction; + +/** + *

+ * JUnit 4 based unit test for verifying that 'before' and 'after' + * methods of {@link TestExecutionListener TestExecutionListeners} as well as + * {@link BeforeTransaction @BeforeTransaction} and + * {@link AfterTransaction @AfterTransaction} methods can fail a test in a JUnit + * 3.8 environment, as requested in SPR-3960. + *

+ * + * @author Sam Brannen + * @since 2.5 + */ +@RunWith(Parameterized.class) +public class FailingBeforeAndAfterMethodsTests { + + protected final Class clazz; + + + public FailingBeforeAndAfterMethodsTests(final Class clazz) { + this.clazz = clazz; + } + + @Parameters + public static Collection testData() { + return Arrays.asList(new Object[][] { + + { AlwaysFailingBeforeTestMethodTestCase.class }, + + { AlwaysFailingAfterTestMethodTestCase.class }, + + { FailingBeforeTransactionalTestCase.class }, + + { FailingAfterTransactionalTestCase.class } + + }); + } + + @Test + public void runTestAndAssertCounters() throws Exception { + final String testName = "testNothing"; + final TestCase testCase = (TestCase) this.clazz.newInstance(); + testCase.setName(testName); + TestResult testResult = testCase.run(); + assertEquals("Verifying number of errors for test method [" + testName + "] and class [" + this.clazz + "].", + 0, testResult.errorCount()); + assertEquals("Verifying number of failures for test method [" + testName + "] and class [" + this.clazz + "].", + 1, testResult.failureCount()); + } + + + static class AlwaysFailingBeforeTestMethodTestExecutionListener extends AbstractTestExecutionListener { + + @Override + public void beforeTestMethod(TestContext testContext) { + junit.framework.Assert.fail("always failing beforeTestMethod()"); + } + } + + + static class AlwaysFailingAfterTestMethodTestExecutionListener extends AbstractTestExecutionListener { + + @Override + public void afterTestMethod(TestContext testContext) { + junit.framework.Assert.fail("always failing afterTestMethod()"); + } + } + + + @TestExecutionListeners(value = { AlwaysFailingBeforeTestMethodTestExecutionListener.class }, inheritListeners = false) + public static class AlwaysFailingBeforeTestMethodTestCase extends AbstractJUnit38SpringContextTests { + + public void testNothing() { + } + } + + + @TestExecutionListeners(value = { AlwaysFailingAfterTestMethodTestExecutionListener.class }, inheritListeners = false) + public static class AlwaysFailingAfterTestMethodTestCase extends AbstractJUnit38SpringContextTests { + + public void testNothing() { + } + } + + + @ContextConfiguration(locations = { "FailingBeforeAndAfterMethodsTests-context.xml" }) + public static class FailingBeforeTransactionalTestCase extends AbstractTransactionalJUnit38SpringContextTests { + + public void testNothing() { + } + + @BeforeTransaction + public void beforeTransaction() { + fail("always failing beforeTransaction()"); + } + } + + @ContextConfiguration(locations = { "FailingBeforeAndAfterMethodsTests-context.xml" }) + public static class FailingAfterTransactionalTestCase extends AbstractTransactionalJUnit38SpringContextTests { + + public void testNothing() { + } + + @AfterTransaction + public void afterTransaction() { + fail("always failing afterTransaction()"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/ProfileValueJUnit38SpringContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/ProfileValueJUnit38SpringContextTests.java new file mode 100644 index 00000000000..8c48a84d70e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/ProfileValueJUnit38SpringContextTests.java @@ -0,0 +1,146 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit38; + +import junit.framework.TestCase; +import junit.framework.TestResult; + +import org.springframework.test.annotation.IfProfileValue; +import org.springframework.test.annotation.ProfileValueSource; +import org.springframework.test.annotation.ProfileValueSourceConfiguration; +import org.springframework.test.annotation.SystemProfileValueSource; +import org.springframework.test.context.TestExecutionListeners; + +/** + * Verifies proper handling of {@link IfProfileValue @IfProfileValue} and + * {@link ProfileValueSourceConfiguration @ProfileValueSourceConfiguration} in + * conjunction with {@link AbstractJUnit38SpringContextTests}. + * + * @author Sam Brannen + * @since 2.5 + */ +public class ProfileValueJUnit38SpringContextTests extends TestCase { + + private static final String NAME = "ProfileValueAnnotationAwareTransactionalTests.profile_value.name"; + + private static final String VALUE = "enigma"; + + + public ProfileValueJUnit38SpringContextTests() { + System.setProperty(NAME, VALUE); + } + + + private void runTestAndAssertCounters(Class testCaseType, + String testName, int expectedInvocationCount, int expectedErrorCount, + int expectedFailureCount) throws Exception { + + DefaultProfileValueSourceTestCase testCase = testCaseType.newInstance(); + testCase.setName(testName); + TestResult testResult = testCase.run(); + assertEquals("Verifying number of invocations for test method [" + testName + "].", expectedInvocationCount, + testCase.invocationCount); + assertEquals("Verifying number of errors for test method [" + testName + "].", expectedErrorCount, + testResult.errorCount()); + assertEquals("Verifying number of failures for test method [" + testName + "].", expectedFailureCount, + testResult.failureCount()); + } + + private void runTests(final Class testCaseType) throws Exception { + runTestAndAssertCounters(testCaseType, "testIfProfileValueEmpty", 0, 0, 0); + runTestAndAssertCounters(testCaseType, "testIfProfileValueDisabledViaWrongName", 0, 0, 0); + runTestAndAssertCounters(testCaseType, "testIfProfileValueDisabledViaWrongValue", 0, 0, 0); + runTestAndAssertCounters(testCaseType, "testIfProfileValueEnabledViaSingleValue", 1, 0, 0); + runTestAndAssertCounters(testCaseType, "testIfProfileValueEnabledViaMultipleValues", 1, 0, 0); + runTestAndAssertCounters(testCaseType, "testIfProfileValueNotConfigured", 1, 0, 0); + } + + public void testDefaultProfileValueSource() throws Exception { + assertEquals("Verifying the type of the configured ProfileValueSource.", SystemProfileValueSource.class, + new DefaultProfileValueSourceTestCase().getProfileValueSource().getClass()); + runTests(DefaultProfileValueSourceTestCase.class); + } + + public void testHardCodedProfileValueSource() throws Exception { + assertEquals("Verifying the type of the configured ProfileValueSource.", HardCodedProfileValueSource.class, + new HardCodedProfileValueSourceTestCase().getProfileValueSource().getClass()); + runTests(HardCodedProfileValueSourceTestCase.class); + } + + + /** + * Note that {@link TestExecutionListeners @TestExecutionListeners} is + * explicitly configured with an empty list, thus disabling all default + * listeners. + */ + @TestExecutionListeners(value = {}, inheritListeners = false) + public static class DefaultProfileValueSourceTestCase extends AbstractJUnit38SpringContextTests { + + int invocationCount = 0; + + public ProfileValueSource getProfileValueSource() { + return super.profileValueSource; + } + + @IfProfileValue(name = NAME, value = "") + public void testIfProfileValueEmpty() { + this.invocationCount++; + fail("An empty profile value should throw an IllegalArgumentException."); + } + + @IfProfileValue(name = NAME + "X", value = VALUE) + public void testIfProfileValueDisabledViaWrongName() { + this.invocationCount++; + fail("The body of a disabled test should never be executed!"); + } + + @IfProfileValue(name = NAME, value = VALUE + "X") + public void testIfProfileValueDisabledViaWrongValue() { + this.invocationCount++; + fail("The body of a disabled test should never be executed!"); + } + + @IfProfileValue(name = NAME, value = VALUE) + public void testIfProfileValueEnabledViaSingleValue() { + this.invocationCount++; + } + + @IfProfileValue(name = NAME, values = { "foo", VALUE, "bar" }) + public void testIfProfileValueEnabledViaMultipleValues() { + this.invocationCount++; + } + + public void testIfProfileValueNotConfigured() { + this.invocationCount++; + } + } + + + @ProfileValueSourceConfiguration(HardCodedProfileValueSource.class) + public static class HardCodedProfileValueSourceTestCase extends DefaultProfileValueSourceTestCase { + + } + + + public static class HardCodedProfileValueSource implements ProfileValueSource { + + public String get(final String key) { + return (key.equals(NAME) ? VALUE : null); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/RepeatedJUnit38SpringContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/RepeatedJUnit38SpringContextTests.java new file mode 100644 index 00000000000..c39c50383a7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit38/RepeatedJUnit38SpringContextTests.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit38; + +import junit.framework.TestCase; + +import org.springframework.test.annotation.Repeat; +import org.springframework.test.context.TestExecutionListeners; + +/** + * Unit test for {@link AbstractJUnit38SpringContextTests} which focuses on + * proper support of the {@link Repeat @Repeat} annotation. + * + * @author Sam Brannen + * @since 2.5 + */ +public class RepeatedJUnit38SpringContextTests extends TestCase { + + public RepeatedJUnit38SpringContextTests() throws Exception { + super(); + } + + public RepeatedJUnit38SpringContextTests(final String name) throws Exception { + super(name); + } + + private void assertRepetitions(final String testName, final int expectedNumInvocations) throws Exception { + final RepeatedTestCase repeatedTestCase = new RepeatedTestCase(testName); + repeatedTestCase.run(); + assertEquals("Verifying number of invocations for test method [" + testName + "].", expectedNumInvocations, + repeatedTestCase.invocationCount); + } + + public void testRepeatAnnotationSupport() throws Exception { + assertRepetitions("testNonAnnotated", 1); + assertRepetitions("testNegativeRepeatValue", 1); + assertRepetitions("testDefaultRepeatValue", 1); + assertRepetitions("testRepeatedFiveTimes", 5); + } + + + /** + * Note that {@link TestExecutionListeners @TestExecutionListeners} is + * explicitly configured with an empty list, thus disabling all default + * listeners. + */ + @TestExecutionListeners(value = {}, inheritListeners = false) + protected static class RepeatedTestCase extends AbstractJUnit38SpringContextTests { + + int invocationCount = 0; + + + public RepeatedTestCase(final String name) throws Exception { + super(name); + } + + @Override + protected void setUp() throws Exception { + this.invocationCount++; + } + + public void testNonAnnotated() { + /* no-op */ + } + + @Repeat(-5) + public void testNegativeRepeatValue() { + /* no-op */ + } + + @Repeat + public void testDefaultRepeatValue() { + /* no-op */ + } + + @Repeat(5) + public void testRepeatedFiveTimes() { + /* no-op */ + } + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/AbsolutePathSpringJUnit4ClassRunnerAppCtxTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/AbsolutePathSpringJUnit4ClassRunnerAppCtxTests.java new file mode 100644 index 00000000000..ea26f941cc3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/AbsolutePathSpringJUnit4ClassRunnerAppCtxTests.java @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import org.junit.runner.RunWith; + +import org.springframework.test.context.ContextConfiguration; + +/** + * Extension of {@link SpringJUnit4ClassRunnerAppCtxTests}, which verifies that + * we can specify an explicit, absolute path location for our + * application context. + * + * @author Sam Brannen + * @since 2.5 + * @see SpringJUnit4ClassRunnerAppCtxTests + * @see ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests + * @see RelativePathSpringJUnit4ClassRunnerAppCtxTests + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { SpringJUnit4ClassRunnerAppCtxTests.DEFAULT_CONTEXT_RESOURCE_PATH }) +public class AbsolutePathSpringJUnit4ClassRunnerAppCtxTests extends SpringJUnit4ClassRunnerAppCtxTests { + /* all tests are in the parent class. */ +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/AbstractTransactionalSpringRunnerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/AbstractTransactionalSpringRunnerTests.java new file mode 100644 index 00000000000..7491de80d10 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/AbstractTransactionalSpringRunnerTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import org.springframework.jdbc.BadSqlGrammarException; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.test.annotation.NotTransactional; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.transaction.annotation.Transactional; + +/** + * Abstract base class for verifying support of Spring's + * {@link Transactional @Transactional} and + * {@link NotTransactional @NotTransactional} annotations. + * + * @author Sam Brannen + * @since 2.5 + * @see ClassLevelTransactionalSpringRunnerTests + * @see MethodLevelTransactionalSpringRunnerTests + * @see Transactional + * @see NotTransactional + */ +@ContextConfiguration(locations = {"transactionalTests-context.xml"}) +public abstract class AbstractTransactionalSpringRunnerTests { + + protected static final String BOB = "bob"; + protected static final String JANE = "jane"; + protected static final String SUE = "sue"; + protected static final String LUKE = "luke"; + protected static final String LEIA = "leia"; + protected static final String YODA = "yoda"; + + + protected static int clearPersonTable(SimpleJdbcTemplate simpleJdbcTemplate) { + return simpleJdbcTemplate.update("DELETE FROM person"); + } + + protected static void createPersonTable(SimpleJdbcTemplate simpleJdbcTemplate) { + try { + simpleJdbcTemplate.update("CREATE TABLE person (name VARCHAR(20) NOT NULL, PRIMARY KEY(name))"); + } + catch (BadSqlGrammarException bsge) { + // ignore + } + } + + protected static int countRowsInPersonTable(SimpleJdbcTemplate simpleJdbcTemplate) { + return simpleJdbcTemplate.queryForInt("SELECT COUNT(0) FROM person"); + } + + protected static int addPerson(SimpleJdbcTemplate simpleJdbcTemplate, String name) { + return simpleJdbcTemplate.update("INSERT INTO person VALUES(?)", name); + } + + protected static int deletePerson(SimpleJdbcTemplate simpleJdbcTemplate, String name) { + return simpleJdbcTemplate.update("DELETE FROM person WHERE name=?", name); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/BeforeAndAfterTransactionAnnotationTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/BeforeAndAfterTransactionAnnotationTests-context.xml new file mode 100644 index 00000000000..666f357b7bc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/BeforeAndAfterTransactionAnnotationTests-context.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/BeforeAndAfterTransactionAnnotationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/BeforeAndAfterTransactionAnnotationTests.java new file mode 100644 index 00000000000..044bb3f8beb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/BeforeAndAfterTransactionAnnotationTests.java @@ -0,0 +1,140 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import javax.annotation.Resource; +import javax.sql.DataSource; + +import static org.junit.Assert.assertEquals; +import static org.springframework.test.transaction.TransactionTestUtils.assertInTransaction; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.transaction.AfterTransaction; +import org.springframework.test.context.transaction.BeforeTransaction; +import org.springframework.test.context.transaction.TransactionalTestExecutionListener; +import org.springframework.transaction.annotation.Transactional; + +/** + * JUnit 4 based unit test which verifies + * {@link BeforeTransaction @BeforeTransaction} and + * {@link AfterTransaction @AfterTransaction} behavior. + * + * @author Sam Brannen + * @since 2.5 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +@TestExecutionListeners({TransactionalTestExecutionListener.class}) +public class BeforeAndAfterTransactionAnnotationTests extends AbstractTransactionalSpringRunnerTests { + + protected static SimpleJdbcTemplate simpleJdbcTemplate; + + protected static int numBeforeTransactionCalls = 0; + protected static int numAfterTransactionCalls = 0; + + protected boolean inTransaction = false; + + + @BeforeClass + public static void beforeClass() { + BeforeAndAfterTransactionAnnotationTests.numBeforeTransactionCalls = 0; + BeforeAndAfterTransactionAnnotationTests.numAfterTransactionCalls = 0; + } + + @AfterClass + public static void afterClass() { + assertEquals("Verifying the final number of rows in the person table after all tests.", 3, + countRowsInPersonTable(simpleJdbcTemplate)); + assertEquals("Verifying the total number of calls to beforeTransaction().", 2, + BeforeAndAfterTransactionAnnotationTests.numBeforeTransactionCalls); + assertEquals("Verifying the total number of calls to afterTransaction().", 2, + BeforeAndAfterTransactionAnnotationTests.numAfterTransactionCalls); + } + + + @BeforeTransaction + public void beforeTransaction() { + assertInTransaction(false); + this.inTransaction = true; + BeforeAndAfterTransactionAnnotationTests.numBeforeTransactionCalls++; + clearPersonTable(simpleJdbcTemplate); + assertEquals("Adding yoda", 1, addPerson(simpleJdbcTemplate, YODA)); + } + + @AfterTransaction + public void afterTransaction() { + assertInTransaction(false); + this.inTransaction = false; + BeforeAndAfterTransactionAnnotationTests.numAfterTransactionCalls++; + assertEquals("Deleting yoda", 1, deletePerson(simpleJdbcTemplate, YODA)); + assertEquals("Verifying the number of rows in the person table after a transactional test method.", 0, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Before + public void before() { + assertEquals("Verifying the number of rows in the person table before a test method.", (this.inTransaction ? 1 : 0), countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Test + @Transactional + public void transactionalMethod1() { + assertInTransaction(true); + assertEquals("Adding jane", 1, addPerson(simpleJdbcTemplate, JANE)); + assertEquals("Verifying the number of rows in the person table within transactionalMethod1().", 2, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Test + @Transactional + public void transactionalMethod2() { + assertInTransaction(true); + assertEquals("Adding jane", 1, addPerson(simpleJdbcTemplate, JANE)); + assertEquals("Adding sue", 1, addPerson(simpleJdbcTemplate, SUE)); + assertEquals("Verifying the number of rows in the person table within transactionalMethod2().", 3, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Test + public void nonTransactionalMethod() { + assertInTransaction(false); + assertEquals("Adding luke", 1, addPerson(simpleJdbcTemplate, LUKE)); + assertEquals("Adding leia", 1, addPerson(simpleJdbcTemplate, LEIA)); + assertEquals("Adding yoda", 1, addPerson(simpleJdbcTemplate, YODA)); + assertEquals("Verifying the number of rows in the person table without a transaction.", 3, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + + public static class DatabaseSetup { + + @Resource + void setDataSource(DataSource dataSource) { + simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); + createPersonTable(simpleJdbcTemplate); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassLevelDisabledSpringRunnerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassLevelDisabledSpringRunnerTests.java new file mode 100644 index 00000000000..3f511783620 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassLevelDisabledSpringRunnerTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.junit.Assert.fail; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.test.annotation.IfProfileValue; +import org.springframework.test.context.TestContext; +import org.springframework.test.context.TestExecutionListener; +import org.springframework.test.context.TestExecutionListeners; + +/** + * @author Juergen Hoeller + */ +@RunWith(SpringJUnit4ClassRunner.class) +@TestExecutionListeners(ClassLevelDisabledSpringRunnerTests.CustomTestExecutionListener.class) +@IfProfileValue(name = "ClassLevelDisabledSpringRunnerTests.profile_value.name", value = "enigmaX") +public class ClassLevelDisabledSpringRunnerTests { + + @Test + public void testIfProfileValueDisabled() { + fail("The body of a disabled test should never be executed!"); + } + + + public static class CustomTestExecutionListener implements TestExecutionListener { + + public void prepareTestInstance(TestContext testContext) throws Exception { + fail("A listener method for a disabled test should never be executed!"); + } + + public void beforeTestMethod(TestContext testContext) throws Exception { + fail("A listener method for a disabled test should never be executed!"); + } + + public void afterTestMethod(TestContext testContext) throws Exception { + fail("A listener method for a disabled test should never be executed!"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassLevelTransactionalSpringRunnerTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassLevelTransactionalSpringRunnerTests-context.xml new file mode 100644 index 00000000000..9df7964a913 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassLevelTransactionalSpringRunnerTests-context.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassLevelTransactionalSpringRunnerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassLevelTransactionalSpringRunnerTests.java new file mode 100644 index 00000000000..0007c9bbee4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassLevelTransactionalSpringRunnerTests.java @@ -0,0 +1,118 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.junit.Assert.assertEquals; +import static org.springframework.test.transaction.TransactionTestUtils.assertInTransaction; + +import javax.annotation.Resource; +import javax.sql.DataSource; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.test.annotation.NotTransactional; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestExecutionListener; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; +import org.springframework.test.context.support.DirtiesContextTestExecutionListener; +import org.springframework.test.context.transaction.TransactionalTestExecutionListener; +import org.springframework.transaction.annotation.Transactional; + +/** + *

+ * JUnit 4 based unit test which verifies support of Spring's + * {@link Transactional @Transactional}, + * {@link NotTransactional @NotTransactional}, + * {@link TestExecutionListeners @TestExecutionListeners}, and + * {@link ContextConfiguration @ContextConfiguration} annotations in conjunction + * with the {@link SpringJUnit4ClassRunner} and the following + * {@link TestExecutionListener TestExecutionListeners}: + *

+ *
    + *
  • {@link DependencyInjectionTestExecutionListener}
  • + *
  • {@link DirtiesContextTestExecutionListener}
  • + *
  • {@link TransactionalTestExecutionListener}
  • + *
+ *

+ * This class specifically tests usage of @Transactional + * defined at the class level. + *

+ * + * @author Sam Brannen + * @since 2.5 + * @see MethodLevelTransactionalSpringRunnerTests + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +@Transactional +public class ClassLevelTransactionalSpringRunnerTests extends AbstractTransactionalSpringRunnerTests { + + protected static SimpleJdbcTemplate simpleJdbcTemplate; + + + @AfterClass + public static void verifyFinalTestData() { + assertEquals("Verifying the final number of rows in the person table after all tests.", 4, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Before + public void verifyInitialTestData() { + clearPersonTable(simpleJdbcTemplate); + assertEquals("Adding bob", 1, addPerson(simpleJdbcTemplate, BOB)); + assertEquals("Verifying the initial number of rows in the person table.", 1, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + + @Test + public void modifyTestDataWithinTransaction() { + assertInTransaction(true); + assertEquals("Deleting bob", 1, deletePerson(simpleJdbcTemplate, BOB)); + assertEquals("Adding jane", 1, addPerson(simpleJdbcTemplate, JANE)); + assertEquals("Adding sue", 1, addPerson(simpleJdbcTemplate, SUE)); + assertEquals("Verifying the number of rows in the person table within a transaction.", 2, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Test + @NotTransactional + public void modifyTestDataWithoutTransaction() { + assertInTransaction(false); + assertEquals("Adding luke", 1, addPerson(simpleJdbcTemplate, LUKE)); + assertEquals("Adding leia", 1, addPerson(simpleJdbcTemplate, LEIA)); + assertEquals("Adding yoda", 1, addPerson(simpleJdbcTemplate, YODA)); + assertEquals("Verifying the number of rows in the person table without a transaction.", 4, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + + public static class DatabaseSetup { + + @Resource + public void setDataSource(DataSource dataSource) { + simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); + createPersonTable(simpleJdbcTemplate); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests.java new file mode 100644 index 00000000000..4e9ebb7496c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests.java @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import org.junit.runner.RunWith; + +import org.springframework.test.context.ContextConfiguration; +import org.springframework.util.ResourceUtils; + +/** + * Extension of {@link SpringJUnit4ClassRunnerAppCtxTests}, which verifies that + * we can specify an explicit, classpath location for our application + * context. + * + * @author Sam Brannen + * @since 2.5 + * @see SpringJUnit4ClassRunnerAppCtxTests + * @see #CLASSPATH_CONTEXT_RESOURCE_PATH + * @see AbsolutePathSpringJUnit4ClassRunnerAppCtxTests + * @see RelativePathSpringJUnit4ClassRunnerAppCtxTests + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests.CLASSPATH_CONTEXT_RESOURCE_PATH }) +public class ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests extends SpringJUnit4ClassRunnerAppCtxTests { + + /** + * Classpath-based resource path for the application context configuration + * for {@link SpringJUnit4ClassRunnerAppCtxTests}: + * "classpath:/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests-context.xml" + * + * @see SpringJUnit4ClassRunnerAppCtxTests#DEFAULT_CONTEXT_RESOURCE_PATH + * @see ResourceUtils#CLASSPATH_URL_PREFIX + */ + public static final String CLASSPATH_CONTEXT_RESOURCE_PATH = ResourceUtils.CLASSPATH_URL_PREFIX + + SpringJUnit4ClassRunnerAppCtxTests.DEFAULT_CONTEXT_RESOURCE_PATH; + + /* all tests are in the parent class. */ +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ConcreteTransactionalJUnit4SpringContextTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ConcreteTransactionalJUnit4SpringContextTests-context.xml new file mode 100644 index 00000000000..a219470ce63 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ConcreteTransactionalJUnit4SpringContextTests-context.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ConcreteTransactionalJUnit4SpringContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ConcreteTransactionalJUnit4SpringContextTests.java new file mode 100644 index 00000000000..21e4a76860f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ConcreteTransactionalJUnit4SpringContextTests.java @@ -0,0 +1,236 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.transaction.TransactionTestUtils.assertInTransaction; +import static org.springframework.test.transaction.TransactionTestUtils.inTransaction; + +import javax.annotation.Resource; +import javax.sql.DataSource; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.beans.Employee; +import org.springframework.beans.Pet; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.BadSqlGrammarException; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.test.annotation.NotTransactional; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.transaction.AfterTransaction; +import org.springframework.test.context.transaction.BeforeTransaction; +import org.springframework.test.jdbc.SimpleJdbcTestUtils; + +/** + * Combined unit test for {@link AbstractJUnit4SpringContextTests} and + * {@link AbstractTransactionalJUnit4SpringContextTests}. + * + * @author Sam Brannen + * @since 2.5 + */ +@ContextConfiguration +public class ConcreteTransactionalJUnit4SpringContextTests extends AbstractTransactionalJUnit4SpringContextTests + implements BeanNameAware, InitializingBean { + + protected static final String BOB = "bob"; + protected static final String JANE = "jane"; + protected static final String SUE = "sue"; + protected static final String LUKE = "luke"; + protected static final String LEIA = "leia"; + protected static final String YODA = "yoda"; + + + private boolean beanInitialized = false; + + private String beanName = "replace me with [" + getClass().getName() + "]"; + + private Employee employee; + + @Autowired + private Pet pet; + + @Autowired(required = false) + protected Long nonrequiredLong; + + @Resource + protected String foo; + + protected String bar; + + + protected static int clearPersonTable(final SimpleJdbcTemplate simpleJdbcTemplate) { + return SimpleJdbcTestUtils.deleteFromTables(simpleJdbcTemplate, "person"); + } + + protected static void createPersonTable(final SimpleJdbcTemplate simpleJdbcTemplate) { + try { + simpleJdbcTemplate.update("CREATE TABLE person (name VARCHAR(20) NOT NULL, PRIMARY KEY(name))"); + } + catch (final BadSqlGrammarException bsge) { + /* ignore */ + } + } + + protected static int countRowsInPersonTable(final SimpleJdbcTemplate simpleJdbcTemplate) { + return SimpleJdbcTestUtils.countRowsInTable(simpleJdbcTemplate, "person"); + } + + protected static int addPerson(final SimpleJdbcTemplate simpleJdbcTemplate, final String name) { + return simpleJdbcTemplate.update("INSERT INTO person VALUES(?)", name); + } + + protected static int deletePerson(final SimpleJdbcTemplate simpleJdbcTemplate, final String name) { + return simpleJdbcTemplate.update("DELETE FROM person WHERE name=?", name); + } + + + @Resource + public void setDataSource(DataSource dataSource) { + super.setDataSource(dataSource); + } + + @Autowired + protected final void setEmployee(final Employee employee) { + this.employee = employee; + } + + @Resource + protected final void setBar(final String bar) { + this.bar = bar; + } + + public final void setBeanName(final String beanName) { + this.beanName = beanName; + } + + public final void afterPropertiesSet() throws Exception { + this.beanInitialized = true; + } + + + @Test + @NotTransactional + public final void verifyApplicationContext() { + assertInTransaction(false); + assertNotNull("The application context should have been set due to ApplicationContextAware semantics.", + super.applicationContext); + } + + @Test + @NotTransactional + public final void verifyBeanInitialized() { + assertInTransaction(false); + assertTrue("This test bean should have been initialized due to InitializingBean semantics.", + this.beanInitialized); + } + + @Test + @NotTransactional + public final void verifyBeanNameSet() { + assertInTransaction(false); + assertEquals("The bean name of this test instance should have been set to the fully qualified class name " + + "due to BeanNameAware semantics.", getClass().getName(), this.beanName); + } + + @Test + @NotTransactional + public final void verifyAnnotationAutowiredFields() { + assertInTransaction(false); + assertNull("The nonrequiredLong property should NOT have been autowired.", this.nonrequiredLong); + assertNotNull("The pet field should have been autowired.", this.pet); + assertEquals("Fido", this.pet.getName()); + } + + @Test + @NotTransactional + public final void verifyAnnotationAutowiredMethods() { + assertInTransaction(false); + assertNotNull("The employee setter method should have been autowired.", this.employee); + assertEquals("John Smith", this.employee.getName()); + } + + @Test + @NotTransactional + public final void verifyResourceAnnotationWiredFields() { + assertInTransaction(false); + assertEquals("The foo field should have been wired via @Resource.", "Foo", this.foo); + } + + @Test + @NotTransactional + public final void verifyResourceAnnotationWiredMethods() { + assertInTransaction(false); + assertEquals("The bar method should have been wired via @Resource.", "Bar", this.bar); + } + + + @BeforeTransaction + public void beforeTransaction() { + assertEquals("Verifying the number of rows in the person table before a transactional test method.", 1, + countRowsInPersonTable(super.simpleJdbcTemplate)); + assertEquals("Adding yoda", 1, addPerson(super.simpleJdbcTemplate, YODA)); + } + + @Before + public void setUp() throws Exception { + assertEquals("Verifying the number of rows in the person table before a test method.", + (inTransaction() ? 2 : 1), countRowsInPersonTable(super.simpleJdbcTemplate)); + } + + @Test + public void modifyTestDataWithinTransaction() { + assertInTransaction(true); + assertEquals("Adding jane", 1, addPerson(super.simpleJdbcTemplate, JANE)); + assertEquals("Adding sue", 1, addPerson(super.simpleJdbcTemplate, SUE)); + assertEquals("Verifying the number of rows in the person table in modifyTestDataWithinTransaction().", 4, + countRowsInPersonTable(super.simpleJdbcTemplate)); + } + + @After + public void tearDown() throws Exception { + assertEquals("Verifying the number of rows in the person table after a test method.", + (inTransaction() ? 4 : 1), countRowsInPersonTable(super.simpleJdbcTemplate)); + } + + @AfterTransaction + public void afterTransaction() { + assertEquals("Deleting yoda", 1, deletePerson(super.simpleJdbcTemplate, YODA)); + assertEquals("Verifying the number of rows in the person table after a transactional test method.", 1, + countRowsInPersonTable(super.simpleJdbcTemplate)); + } + + + public static class DatabaseSetup { + + @Resource + public void setDataSource(DataSource dataSource) { + SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); + createPersonTable(simpleJdbcTemplate); + clearPersonTable(simpleJdbcTemplate); + addPerson(simpleJdbcTemplate, BOB); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackFalseTransactionalSpringRunnerTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackFalseTransactionalSpringRunnerTests-context.xml new file mode 100644 index 00000000000..d9663d7c174 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackFalseTransactionalSpringRunnerTests-context.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackFalseTransactionalSpringRunnerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackFalseTransactionalSpringRunnerTests.java new file mode 100644 index 00000000000..3368cf88c29 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackFalseTransactionalSpringRunnerTests.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.junit.Assert.assertEquals; +import static org.springframework.test.transaction.TransactionTestUtils.assertInTransaction; + +import javax.annotation.Resource; +import javax.sql.DataSource; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.transaction.TransactionConfiguration; +import org.springframework.transaction.annotation.Transactional; + +/** + *

+ * JUnit 4 based unit test which verifies proper transactional behavior when the + * {@link TransactionConfiguration#defaultRollback() defaultRollback} attribute + * of the {@link TransactionConfiguration} annotation is set to false. + * Also tests configuration of the + * {@link TransactionConfiguration#transactionManager() transaction manager name}. + *

+ * + * @author Sam Brannen + * @since 2.5 + * @see TransactionConfiguration + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +@TransactionConfiguration(transactionManager = "txMgr", defaultRollback = false) +@Transactional +public class DefaultRollbackFalseTransactionalSpringRunnerTests extends AbstractTransactionalSpringRunnerTests { + + protected static SimpleJdbcTemplate simpleJdbcTemplate; + + + @AfterClass + public static void verifyFinalTestData() { + assertEquals("Verifying the final number of rows in the person table after all tests.", 2, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Before + public void verifyInitialTestData() { + clearPersonTable(simpleJdbcTemplate); + assertEquals("Adding bob", 1, addPerson(simpleJdbcTemplate, BOB)); + assertEquals("Verifying the initial number of rows in the person table.", 1, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Test + public void modifyTestDataWithinTransaction() { + assertInTransaction(true); + assertEquals("Deleting bob", 1, deletePerson(simpleJdbcTemplate, BOB)); + assertEquals("Adding jane", 1, addPerson(simpleJdbcTemplate, JANE)); + assertEquals("Adding sue", 1, addPerson(simpleJdbcTemplate, SUE)); + assertEquals("Verifying the number of rows in the person table within a transaction.", 2, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + + public static class DatabaseSetup { + + @Resource + public void setDataSource(DataSource dataSource) { + simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); + createPersonTable(simpleJdbcTemplate); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackTrueTransactionalSpringRunnerTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackTrueTransactionalSpringRunnerTests-context.xml new file mode 100644 index 00000000000..1c44b0c01bc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackTrueTransactionalSpringRunnerTests-context.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackTrueTransactionalSpringRunnerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackTrueTransactionalSpringRunnerTests.java new file mode 100644 index 00000000000..70d6f80fad7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/DefaultRollbackTrueTransactionalSpringRunnerTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.junit.Assert.assertEquals; +import static org.springframework.test.transaction.TransactionTestUtils.assertInTransaction; + +import javax.annotation.Resource; +import javax.sql.DataSource; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.transaction.TransactionConfiguration; +import org.springframework.transaction.annotation.Transactional; + +/** + * JUnit 4 based unit test which verifies proper transactional behavior when the + * {@link TransactionConfiguration#defaultRollback() defaultRollback} attribute + * of the {@link TransactionConfiguration} annotation is set to true. + * + * @author Sam Brannen + * @since 2.5 + * @see TransactionConfiguration + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +@TransactionConfiguration(defaultRollback = true) +public class DefaultRollbackTrueTransactionalSpringRunnerTests extends AbstractTransactionalSpringRunnerTests { + + protected static int originalNumRows; + + protected static SimpleJdbcTemplate simpleJdbcTemplate; + + + @AfterClass + public static void verifyFinalTestData() { + assertEquals("Verifying the final number of rows in the person table after all tests.", originalNumRows, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Before + public void verifyInitialTestData() { + originalNumRows = clearPersonTable(simpleJdbcTemplate); + assertEquals("Adding bob", 1, addPerson(simpleJdbcTemplate, BOB)); + assertEquals("Verifying the initial number of rows in the person table.", 1, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Test(timeout = 1000) + @Transactional + public void modifyTestDataWithinTransaction() { + assertInTransaction(true); + assertEquals("Adding jane", 1, addPerson(simpleJdbcTemplate, JANE)); + assertEquals("Adding sue", 1, addPerson(simpleJdbcTemplate, SUE)); + assertEquals("Verifying the number of rows in the person table within a transaction.", 3, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + + public static class DatabaseSetup { + + @Resource + public void setDataSource(DataSource dataSource) { + simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); + createPersonTable(simpleJdbcTemplate); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/EnabledAndIgnoredSpringRunnerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/EnabledAndIgnoredSpringRunnerTests.java new file mode 100644 index 00000000000..dddb935b8b7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/EnabledAndIgnoredSpringRunnerTests.java @@ -0,0 +1,101 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import org.junit.AfterClass; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.test.annotation.IfProfileValue; +import org.springframework.test.annotation.ProfileValueSource; +import org.springframework.test.annotation.ProfileValueSourceConfiguration; +import org.springframework.test.context.TestExecutionListeners; + +/** + * Verifies proper handling of JUnit's {@link org.junit.Ignore @Ignore} and + * Spring's + * {@link org.springframework.test.annotation.IfProfileValue @IfProfileValue} + * and {@link ProfileValueSourceConfiguration @ProfileValueSourceConfiguration} + * (with the implicit, default {@link ProfileValueSource}) + * annotations in conjunction with the {@link SpringJUnit4ClassRunner}. + * + *

Note that {@link TestExecutionListeners @TestExecutionListeners} is + * explicitly configured with an empty list, thus disabling all default + * listeners. + * + * @author Sam Brannen + * @since 2.5 + * @see HardCodedProfileValueSourceSpringRunnerTests + */ +@RunWith(SpringJUnit4ClassRunner.class) +@TestExecutionListeners({}) +public class EnabledAndIgnoredSpringRunnerTests { + + protected static final String NAME = "EnabledAndIgnoredSpringRunnerTests.profile_value.name"; + + protected static final String VALUE = "enigma"; + + protected static int numTestsExecuted = 0; + + + @BeforeClass + public static void setProfileValue() { + numTestsExecuted = 0; + System.setProperty(NAME, VALUE); + } + + @AfterClass + public static void verifyNumTestsExecuted() { + assertEquals("Verifying the number of tests executed.", 3, numTestsExecuted); + } + + @Test + @IfProfileValue(name = NAME, value = VALUE + "X") + public void testIfProfileValueDisabled() { + numTestsExecuted++; + fail("The body of a disabled test should never be executed!"); + } + + @Test + @IfProfileValue(name = NAME, value = VALUE) + public void testIfProfileValueEnabledViaSingleValue() { + numTestsExecuted++; + } + + @Test + @IfProfileValue(name = NAME, values = { "foo", VALUE, "bar" }) + public void testIfProfileValueEnabledViaMultipleValues() { + numTestsExecuted++; + } + + @Test + public void testIfProfileValueNotConfigured() { + numTestsExecuted++; + } + + @Test + @Ignore + public void testJUnitIgnoreAnnotation() { + numTestsExecuted++; + fail("The body of an ignored test should never be executed!"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/FailingBeforeAndAfterMethodsTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/FailingBeforeAndAfterMethodsTests-context.xml new file mode 100644 index 00000000000..3c4fc976b8e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/FailingBeforeAndAfterMethodsTests-context.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/FailingBeforeAndAfterMethodsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/FailingBeforeAndAfterMethodsTests.java new file mode 100644 index 00000000000..a1fcc57abe2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/FailingBeforeAndAfterMethodsTests.java @@ -0,0 +1,165 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestContext; +import org.springframework.test.context.TestExecutionListener; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.support.AbstractTestExecutionListener; +import org.springframework.test.context.transaction.AfterTransaction; +import org.springframework.test.context.transaction.BeforeTransaction; + +/** + *

+ * JUnit 4 based unit test for verifying that 'before' and 'after' + * methods of {@link TestExecutionListener TestExecutionListeners} as well as + * {@link BeforeTransaction @BeforeTransaction} and + * {@link AfterTransaction @AfterTransaction} methods can fail a test in a JUnit + * 4.4 environment, as requested in SPR-3960. + *

+ * + * @author Sam Brannen + * @since 2.5 + */ +@RunWith(Parameterized.class) +public class FailingBeforeAndAfterMethodsTests { + + protected final Class clazz; + + + public FailingBeforeAndAfterMethodsTests(final Class clazz) { + this.clazz = clazz; + } + + @Parameters + public static Collection testData() { + return Arrays.asList(new Object[][] { + + { AlwaysFailingBeforeTestMethodTestCase.class }, + + { AlwaysFailingAfterTestMethodTestCase.class }, + + { FailingBeforeTransactionalTestCase.class }, + + { FailingAfterTransactionalTestCase.class } + + }); + } + + @Test + public void runTestAndAssertCounters() throws Exception { + final FailureTrackingRunListener failureTrackingRunListener = new FailureTrackingRunListener(); + final RunNotifier notifier = new RunNotifier(); + notifier.addListener(failureTrackingRunListener); + + new SpringJUnit4ClassRunner(this.clazz).run(notifier); + assertEquals("Verifying number of failures for test class [" + this.clazz + "].", 1, + failureTrackingRunListener.failureCount); + } + + + static class FailureTrackingRunListener extends RunListener { + + int failureCount = 0; + + + public void testFailure(Failure failure) throws Exception { + this.failureCount++; + } + } + + + static class AlwaysFailingBeforeTestMethodTestExecutionListener extends AbstractTestExecutionListener { + + @Override + public void beforeTestMethod(TestContext testContext) { + org.junit.Assert.fail("always failing beforeTestMethod()"); + } + } + + + static class AlwaysFailingAfterTestMethodTestExecutionListener extends AbstractTestExecutionListener { + + @Override + public void afterTestMethod(TestContext testContext) { + org.junit.Assert.fail("always failing afterTestMethod()"); + } + } + + + @TestExecutionListeners(value = { AlwaysFailingBeforeTestMethodTestExecutionListener.class }, inheritListeners = false) + public static class AlwaysFailingBeforeTestMethodTestCase extends AbstractJUnit4SpringContextTests { + + @Test + public void testNothing() { + } + } + + + @TestExecutionListeners(value = { AlwaysFailingAfterTestMethodTestExecutionListener.class }, inheritListeners = false) + public static class AlwaysFailingAfterTestMethodTestCase extends AbstractJUnit4SpringContextTests { + + @Test + public void testNothing() { + } + } + + + @ContextConfiguration(locations = { "FailingBeforeAndAfterMethodsTests-context.xml" }) + public static class FailingBeforeTransactionalTestCase extends AbstractTransactionalJUnit4SpringContextTests { + + @Test + public void testNothing() { + } + + @BeforeTransaction + public void beforeTransaction() { + org.junit.Assert.fail("always failing beforeTransaction()"); + } + } + + + @ContextConfiguration(locations = { "FailingBeforeAndAfterMethodsTests-context.xml" }) + public static class FailingAfterTransactionalTestCase extends AbstractTransactionalJUnit4SpringContextTests { + + @Test + public void testNothing() { + } + + @AfterTransaction + public void afterTransaction() { + org.junit.Assert.fail("always failing afterTransaction()"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/HardCodedProfileValueSourceSpringRunnerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/HardCodedProfileValueSourceSpringRunnerTests.java new file mode 100644 index 00000000000..f6ecb2aa282 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/HardCodedProfileValueSourceSpringRunnerTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import org.junit.BeforeClass; + +import org.springframework.test.annotation.ProfileValueSource; +import org.springframework.test.annotation.ProfileValueSourceConfiguration; + +/** + *

+ * Verifies proper handling of JUnit's {@link org.junit.Ignore @Ignore} and + * Spring's + * {@link org.springframework.test.annotation.IfProfileValue @IfProfileValue} + * and {@link ProfileValueSourceConfiguration @ProfileValueSourceConfiguration} + * (with an explicit, custom defined {@link ProfileValueSource}) + * annotations in conjunction with the {@link SpringJUnit4ClassRunner}. + *

+ * + * @author Sam Brannen + * @since 2.5 + * @see EnabledAndIgnoredSpringRunnerTests + */ +@ProfileValueSourceConfiguration(HardCodedProfileValueSourceSpringRunnerTests.HardCodedProfileValueSource.class) +public class HardCodedProfileValueSourceSpringRunnerTests extends EnabledAndIgnoredSpringRunnerTests { + + @BeforeClass + public static void setProfileValue() { + numTestsExecuted = 0; + // Set the system property to something other than VALUE as a sanity + // check. + System.setProperty(NAME, "999999999999"); + } + + + public static class HardCodedProfileValueSource implements ProfileValueSource { + + public String get(final String key) { + return (key.equals(NAME) ? VALUE : null); + } + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/InheritedConfigSpringJUnit4ClassRunnerAppCtxTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/InheritedConfigSpringJUnit4ClassRunnerAppCtxTests.java new file mode 100644 index 00000000000..fec86ee6e15 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/InheritedConfigSpringJUnit4ClassRunnerAppCtxTests.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import java.lang.annotation.Inherited; + +import org.springframework.test.context.ContextConfiguration; + +/** + * Extension of {@link SpringJUnit4ClassRunnerAppCtxTests} which verifies that + * the configuration of an application context and dependency injection of a + * test instance function as expected within a class hierarchy, since + * {@link ContextConfiguration configuration} is {@link Inherited inherited}. + * + * @author Sam Brannen + * @since 2.5 + * @see SpringJUnit4ClassRunnerAppCtxTests + */ +public class InheritedConfigSpringJUnit4ClassRunnerAppCtxTests extends SpringJUnit4ClassRunnerAppCtxTests { + /* all tests are in the parent class. */ +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MethodLevelTransactionalSpringRunnerTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MethodLevelTransactionalSpringRunnerTests-context.xml new file mode 100644 index 00000000000..c9e6fa05894 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MethodLevelTransactionalSpringRunnerTests-context.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MethodLevelTransactionalSpringRunnerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MethodLevelTransactionalSpringRunnerTests.java new file mode 100644 index 00000000000..1140a48ade1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MethodLevelTransactionalSpringRunnerTests.java @@ -0,0 +1,118 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.junit.Assert.assertEquals; +import static org.springframework.test.transaction.TransactionTestUtils.assertInTransaction; + +import javax.annotation.Resource; +import javax.sql.DataSource; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestExecutionListener; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; +import org.springframework.test.context.support.DirtiesContextTestExecutionListener; +import org.springframework.test.context.transaction.TransactionalTestExecutionListener; +import org.springframework.transaction.annotation.Transactional; + +/** + *

+ * JUnit 4 based unit test which verifies support of Spring's + * {@link Transactional @Transactional}, + * {@link TestExecutionListeners @TestExecutionListeners}, and + * {@link ContextConfiguration @ContextConfiguration} annotations in conjunction + * with the {@link SpringJUnit4ClassRunner} and the following + * {@link TestExecutionListener TestExecutionListeners}: + *

+ *
    + *
  • {@link DependencyInjectionTestExecutionListener}
  • + *
  • {@link DirtiesContextTestExecutionListener}
  • + *
  • {@link TransactionalTestExecutionListener}
  • + *
+ *

+ * This class specifically tests usage of @Transactional + * defined at the method level. In contrast to + * {@link ClassLevelTransactionalSpringRunnerTests}, this class omits usage of + * @NotTransactional. + *

+ * + * @author Sam Brannen + * @since 2.5 + * @see ClassLevelTransactionalSpringRunnerTests + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, + TransactionalTestExecutionListener.class}) +public class MethodLevelTransactionalSpringRunnerTests extends AbstractTransactionalSpringRunnerTests { + + protected static SimpleJdbcTemplate simpleJdbcTemplate; + + + @AfterClass + public static void verifyFinalTestData() { + assertEquals("Verifying the final number of rows in the person table after all tests.", 4, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Before + public void verifyInitialTestData() { + clearPersonTable(simpleJdbcTemplate); + assertEquals("Adding bob", 1, addPerson(simpleJdbcTemplate, BOB)); + assertEquals("Verifying the initial number of rows in the person table.", 1, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Test + @Transactional + public void modifyTestDataWithinTransaction() { + assertInTransaction(true); + assertEquals("Deleting bob", 1, deletePerson(simpleJdbcTemplate, BOB)); + assertEquals("Adding jane", 1, addPerson(simpleJdbcTemplate, JANE)); + assertEquals("Adding sue", 1, addPerson(simpleJdbcTemplate, SUE)); + assertEquals("Verifying the number of rows in the person table within a transaction.", 2, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Test + public void modifyTestDataWithoutTransaction() { + assertInTransaction(false); + assertEquals("Adding luke", 1, addPerson(simpleJdbcTemplate, LUKE)); + assertEquals("Adding leia", 1, addPerson(simpleJdbcTemplate, LEIA)); + assertEquals("Adding yoda", 1, addPerson(simpleJdbcTemplate, YODA)); + assertEquals("Verifying the number of rows in the person table without a transaction.", 4, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + + public static class DatabaseSetup { + + @Resource + public void setDataSource(DataSource dataSource) { + simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); + createPersonTable(simpleJdbcTemplate); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context1.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context1.xml new file mode 100644 index 00000000000..2f6eda6962f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context1.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context2.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context2.xml new file mode 100644 index 00000000000..cb75b8accd4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context2.xml @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context3.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context3.xml new file mode 100644 index 00000000000..d8c31a18684 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests.java new file mode 100644 index 00000000000..ea739e24c58 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import org.junit.runner.RunWith; + +import org.springframework.test.context.ContextConfiguration; +import org.springframework.util.ResourceUtils; + +/** + * Extension of {@link SpringJUnit4ClassRunnerAppCtxTests}, which verifies that + * we can specify multiple resource locations for our application context, each + * configured differently. + * + * @author Sam Brannen + * @since 2.5 + * @see SpringJUnit4ClassRunnerAppCtxTests + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests.CLASSPATH_RESOURCE_PATH, + MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests.LOCAL_RESOURCE_PATH, + MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests.ABSOLUTE_RESOURCE_PATH }) +public class MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests extends SpringJUnit4ClassRunnerAppCtxTests { + + public static final String CLASSPATH_RESOURCE_PATH = ResourceUtils.CLASSPATH_URL_PREFIX + + "/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context1.xml"; + public static final String LOCAL_RESOURCE_PATH = "MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context2.xml"; + public static final String ABSOLUTE_RESOURCE_PATH = "/org/springframework/test/context/junit4/MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests-context3.xml"; + + /* all tests are in the parent class. */ +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ParameterizedDependencyInjectionTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ParameterizedDependencyInjectionTests-context.xml new file mode 100644 index 00000000000..62206fde4a8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ParameterizedDependencyInjectionTests-context.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ParameterizedDependencyInjectionTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ParameterizedDependencyInjectionTests.java new file mode 100644 index 00000000000..18bf66092b2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/ParameterizedDependencyInjectionTests.java @@ -0,0 +1,115 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import org.springframework.beans.Employee; +import org.springframework.beans.Pet; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestContextManager; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; + +/** + * Simple JUnit 4 based unit test which demonstrates how to use JUnit's + * {@link Parameterized} Runner in conjunction with + * {@link ContextConfiguration @ContextConfiguration}, the + * {@link DependencyInjectionTestExecutionListener}, and a + * {@link TestContextManager} to provide dependency injection to a + * parameterized test instance. + * + * @author Sam Brannen + * @since 2.5 + */ +@RunWith(Parameterized.class) +@ContextConfiguration +@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class }) +public class ParameterizedDependencyInjectionTests { + + private static final List employees = new ArrayList(); + + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private Pet pet; + + private final String employeeBeanName; + private final String employeeName; + + private final TestContextManager testContextManager; + + + public ParameterizedDependencyInjectionTests(final String employeeBeanName, final String employeeName) + throws Exception { + this.testContextManager = new TestContextManager(getClass()); + this.employeeBeanName = employeeBeanName; + this.employeeName = employeeName; + } + + @Parameters + public static Collection employeeData() { + return Arrays.asList(new String[][] { { "employee1", "John Smith" }, { "employee2", "Jane Smith" } }); + } + + @BeforeClass + public static void clearEmployees() { + employees.clear(); + } + + @Before + public void injectDependencies() throws Throwable { + this.testContextManager.prepareTestInstance(this); + } + + @Test + public final void verifyPetAndEmployee() { + + // Verifying dependency injection: + assertNotNull("The pet field should have been autowired.", this.pet); + + // Verifying 'parameterized' support: + final Employee employee = (Employee) this.applicationContext.getBean(this.employeeBeanName); + employees.add(employee); + assertEquals("Verifying the name of the employee configured as bean [" + this.employeeBeanName + "].", + this.employeeName, employee.getName()); + } + + @AfterClass + public static void verifyNumParameterizedRuns() { + assertEquals("Verifying the number of times the parameterized test method was executed.", + employeeData().size(), employees.size()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests-context.properties b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests-context.properties new file mode 100644 index 00000000000..0e62ef734fc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests-context.properties @@ -0,0 +1,5 @@ +cat.(class)=org.springframework.beans.Pet +cat.$0=Garfield + +testString.(class)=java.lang.String +testString.$0=Test String diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests.java new file mode 100644 index 00000000000..45f12200639 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests.java @@ -0,0 +1,78 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.Properties; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.Pet; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.support.GenericPropertiesContextLoader; + +/** + *

+ * JUnit 4 based test class, which verifies the expected functionality of + * {@link SpringJUnit4ClassRunner} in conjunction with support for application + * contexts loaded from Java {@link Properties} files. Specifically, the + * {@link ContextConfiguration#loader() loaderClass} and + * {@link ContextConfiguration#resourceSuffix() resourceSuffix} attributes of + * @ContextConfiguration are tested. + *

+ *

+ * Since no {@link ContextConfiguration#locations() locations} are explicitly + * defined, the {@link ContextConfiguration#resourceSuffix() resourceSuffix} is + * set to "-context.properties", and + * {@link ContextConfiguration#generateDefaultLocations() generateDefaultLocations} + * is left set to its default value of true, this test class's + * dependencies will be injected via + * {@link Autowired annotation-based autowiring} from beans defined in the + * {@link ApplicationContext} loaded from the default classpath resource: "/org/springframework/test/junit4/PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests-context.properties". + *

+ * + * @author Sam Brannen + * @since 2.5 + * @see GenericPropertiesContextLoader + * @see SpringJUnit4ClassRunnerAppCtxTests + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(loader = GenericPropertiesContextLoader.class) +public class PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests { + + @Autowired + private Pet cat; + + @Autowired + private String testString; + + + @Test + public void verifyAnnotationAutowiredFields() { + assertNotNull("The cat field should have been autowired.", this.cat); + assertEquals("Garfield", this.cat.getName()); + + assertNotNull("The testString field should have been autowired.", this.testString); + assertEquals("Test String", this.testString); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RelativePathSpringJUnit4ClassRunnerAppCtxTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RelativePathSpringJUnit4ClassRunnerAppCtxTests.java new file mode 100644 index 00000000000..478874a7473 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RelativePathSpringJUnit4ClassRunnerAppCtxTests.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import org.junit.runner.RunWith; + +import org.springframework.test.context.ContextConfiguration; + +/** + * Extension of {@link SpringJUnit4ClassRunnerAppCtxTests}, which verifies that + * we can specify an explicit, relative path location for our + * application context. + * + * @author Sam Brannen + * @since 2.5 + * @see SpringJUnit4ClassRunnerAppCtxTests + * @see AbsolutePathSpringJUnit4ClassRunnerAppCtxTests + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "SpringJUnit4ClassRunnerAppCtxTests-context.xml" }) +public class RelativePathSpringJUnit4ClassRunnerAppCtxTests extends SpringJUnit4ClassRunnerAppCtxTests { + /* all tests are in the parent class. */ +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RepeatedSpringMethodRoadieTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RepeatedSpringMethodRoadieTests.java new file mode 100644 index 00000000000..c0de6008f38 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RepeatedSpringMethodRoadieTests.java @@ -0,0 +1,140 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.junit.Assert.assertEquals; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; + +import org.easymock.MockControl; +import org.easymock.classextension.MockClassControl; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.internal.runners.TestClass; +import org.junit.runner.Description; +import org.junit.runner.RunWith; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import org.springframework.test.annotation.Repeat; +import org.springframework.test.annotation.Timed; +import org.springframework.test.context.TestContextManager; + +/** + * Unit test for {@link SpringMethodRoadie} which focuses on proper support of + * the {@link Repeat @Repeat} annotation. + * + * @author Sam Brannen + * @since 2.5 + */ +@RunWith(Parameterized.class) +public class RepeatedSpringMethodRoadieTests { + + protected final String methodName; + protected final int expectedNumInvocations; + + protected final MockControl notifierMockControl = MockClassControl.createNiceControl(RunNotifier.class); + protected final RunNotifier notifier = (RunNotifier) this.notifierMockControl.getMock(); + + protected final MockControl descriptionMockControl = MockClassControl.createNiceControl(Description.class); + protected final Description description = (Description) this.descriptionMockControl.getMock(); + + protected final MockControl testContextManagerMockControl = MockClassControl.createNiceControl(TestContextManager.class); + protected final TestContextManager testContextManager = (TestContextManager) this.testContextManagerMockControl.getMock(); + + + public RepeatedSpringMethodRoadieTests(final String methodName, final int expectedNumInvocations) throws Exception { + this.methodName = methodName; + this.expectedNumInvocations = expectedNumInvocations; + } + + @Parameters + public static Collection repetitionData() { + return Arrays.asList(new Object[][] { { "testNonAnnotated", 1 }, { "testNegativeRepeatValue", 1 }, + { "testDefaultRepeatValue", 1 }, { "testRepeatedFiveTimes", 5 } }); + } + + @Test + public void assertRepetitions() throws Exception { + + final Class clazz = RepeatedTestCase.class; + final TestClass testClass = new TestClass(clazz); + final RepeatedTestCase testInstance = clazz.newInstance(); + final Method method = clazz.getMethod(this.methodName, (Class[]) null); + final SpringTestMethod testMethod = new SpringTestMethod(method, testClass); + + new SpringMethodRoadie(this.testContextManager, testInstance, testMethod, this.notifier, this.description).run(); + + assertEquals("Verifying number of @Test invocations for test method [" + this.methodName + "].", + this.expectedNumInvocations, testInstance.invocationCount); + assertEquals("Verifying number of @Before invocations for test method [" + this.methodName + "].", + this.expectedNumInvocations, testInstance.beforeCount); + assertEquals("Verifying number of @After invocations for test method [" + this.methodName + "].", + this.expectedNumInvocations, testInstance.afterCount); + } + + + protected static class RepeatedTestCase { + + int beforeCount = 0; + int afterCount = 0; + int invocationCount = 0; + + + @Before + protected void setUp() throws Exception { + this.beforeCount++; + } + + @After + protected void tearDown() throws Exception { + this.afterCount++; + } + + @Test + @Timed(millis = 10000) + public void testNonAnnotated() { + this.invocationCount++; + } + + @Test + @Repeat(-5) + @Timed(millis = 10000) + public void testNegativeRepeatValue() { + this.invocationCount++; + } + + @Test + @Repeat + @Timed(millis = 10000) + public void testDefaultRepeatValue() { + this.invocationCount++; + } + + @Test + @Repeat(5) + @Timed(millis = 10000) + public void testRepeatedFiveTimes() { + this.invocationCount++; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests-context.xml new file mode 100644 index 00000000000..44a8ae545cd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests-context.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests.java new file mode 100644 index 00000000000..a3945a4ed4a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.junit.Assert.assertEquals; +import static org.springframework.test.transaction.TransactionTestUtils.assertInTransaction; + +import javax.annotation.Resource; +import javax.sql.DataSource; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.test.annotation.Rollback; +import org.springframework.test.context.ContextConfiguration; + +/** + * Extension of {@link DefaultRollbackFalseTransactionalSpringRunnerTests} which + * tests method-level rollback override behavior via the + * {@link Rollback @Rollback} annotation. + * + * @author Sam Brannen + * @since 2.5 + * @see Rollback + */ +@ContextConfiguration +public class RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests extends + DefaultRollbackFalseTransactionalSpringRunnerTests { + + protected static int originalNumRows; + + protected static SimpleJdbcTemplate simpleJdbcTemplate; + + + @AfterClass + public static void verifyFinalTestData() { + assertEquals("Verifying the final number of rows in the person table after all tests.", originalNumRows, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Before + @Override + public void verifyInitialTestData() { + originalNumRows = clearPersonTable(simpleJdbcTemplate); + assertEquals("Adding bob", 1, addPerson(simpleJdbcTemplate, BOB)); + assertEquals("Verifying the initial number of rows in the person table.", 1, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Test + @Rollback(true) + @Override + public void modifyTestDataWithinTransaction() { + assertInTransaction(true); + assertEquals("Deleting bob", 1, deletePerson(simpleJdbcTemplate, BOB)); + assertEquals("Adding jane", 1, addPerson(simpleJdbcTemplate, JANE)); + assertEquals("Adding sue", 1, addPerson(simpleJdbcTemplate, SUE)); + assertEquals("Verifying the number of rows in the person table within a transaction.", 2, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + + public static class DatabaseSetup { + + @Resource + public void setDataSource(DataSource dataSource) { + simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); + createPersonTable(simpleJdbcTemplate); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests-context.xml new file mode 100644 index 00000000000..cda53c569e0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests-context.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests.java new file mode 100644 index 00000000000..d6e59ac5898 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests.java @@ -0,0 +1,86 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.junit.Assert.assertEquals; +import static org.springframework.test.transaction.TransactionTestUtils.assertInTransaction; + +import javax.annotation.Resource; +import javax.sql.DataSource; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.test.annotation.Rollback; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.transaction.annotation.Transactional; + +/** + * Extension of {@link DefaultRollbackTrueTransactionalSpringRunnerTests} which + * tests method-level rollback override behavior via the + * {@link Rollback @Rollback} annotation. + * + * @author Sam Brannen + * @since 2.5 + * @see Rollback + */ +@ContextConfiguration +public class RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests extends + DefaultRollbackTrueTransactionalSpringRunnerTests { + + protected static SimpleJdbcTemplate simpleJdbcTemplate; + + + @AfterClass + public static void verifyFinalTestData() { + assertEquals("Verifying the final number of rows in the person table after all tests.", 3, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + @Before + public void verifyInitialTestData() { + clearPersonTable(simpleJdbcTemplate); + assertEquals("Adding bob", 1, addPerson(simpleJdbcTemplate, BOB)); + assertEquals("Verifying the initial number of rows in the person table.", 1, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + + @Test + @Transactional + @Rollback(false) + public void modifyTestDataWithinTransaction() { + assertInTransaction(true); + assertEquals("Adding jane", 1, addPerson(simpleJdbcTemplate, JANE)); + assertEquals("Adding sue", 1, addPerson(simpleJdbcTemplate, SUE)); + assertEquals("Verifying the number of rows in the person table within a transaction.", 3, + countRowsInPersonTable(simpleJdbcTemplate)); + } + + + public static class DatabaseSetup { + + @Resource + public void setDataSource(DataSource dataSource) { + simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); + createPersonTable(simpleJdbcTemplate); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests-context.xml new file mode 100644 index 00000000000..0fa2e2828c3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests-context.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests.java new file mode 100644 index 00000000000..911610179b8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests.java @@ -0,0 +1,171 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import javax.annotation.Resource; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.BeansException; +import org.springframework.beans.Employee; +import org.springframework.beans.Pet; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; +import org.springframework.test.context.support.GenericXmlContextLoader; + +/** + *

+ * SpringJUnit4ClassRunnerAppCtxTests serves as a proof of concept + * JUnit 4 based test class, which verifies the expected functionality of + * {@link SpringJUnit4ClassRunner} in conjunction with the following: + *

+ *
    + *
  • {@link ContextConfiguration @ContextConfiguration}
  • + *
  • {@link Autowired @Autowired}
  • + *
  • {@link Resource @Resource}
  • + *
  • {@link ApplicationContextAware}
  • + *
  • {@link BeanNameAware}
  • + *
  • {@link InitializingBean}
  • + *
+ *

+ * Since no application context resource + * {@link ContextConfiguration#locations() locations} are explicitly declared + * and since the {@link ContextConfiguration#loader() ContextLoader} is left set + * to the default value of {@link GenericXmlContextLoader}, this test class's + * dependencies will be injected via {@link Autowired @Autowired} and + * {@link Resource @Resource} from beans defined in the + * {@link ApplicationContext} loaded from the default classpath resource: "/org/springframework/test/context/junit/SpringJUnit4ClassRunnerAppCtxTests-context.xml". + *

+ * + * @author Sam Brannen + * @since 2.5 + * @see AbsolutePathSpringJUnit4ClassRunnerAppCtxTests + * @see RelativePathSpringJUnit4ClassRunnerAppCtxTests + * @see InheritedConfigSpringJUnit4ClassRunnerAppCtxTests + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class }) +public class SpringJUnit4ClassRunnerAppCtxTests implements ApplicationContextAware, BeanNameAware, InitializingBean { + + /** + * Default resource path for the application context configuration for + * {@link SpringJUnit4ClassRunnerAppCtxTests}: + * "/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests-context.xml" + */ + public static final String DEFAULT_CONTEXT_RESOURCE_PATH = "/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests-context.xml"; + + private ApplicationContext applicationContext; + + private boolean beanInitialized = false; + + private String beanName = "replace me with [" + getClass().getName() + "]"; + + private Employee employee; + + @Autowired + private Pet pet; + + @Autowired(required = false) + protected Long nonrequiredLong; + + @Resource() + protected String foo; + + protected String bar; + + + // ------------------------------------------------------------------------| + + public final void afterPropertiesSet() throws Exception { + this.beanInitialized = true; + } + + public final void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + public final void setBeanName(final String beanName) { + this.beanName = beanName; + } + + @Autowired + protected final void setEmployee(final Employee employee) { + this.employee = employee; + } + + @Resource + protected final void setBar(final String bar) { + this.bar = bar; + } + + // ------------------------------------------------------------------------| + + @Test + public final void verifyApplicationContextSet() { + assertNotNull("The application context should have been set due to ApplicationContextAware semantics.", + this.applicationContext); + } + + @Test + public final void verifyBeanInitialized() { + assertTrue("This test bean should have been initialized due to InitializingBean semantics.", + this.beanInitialized); + } + + @Test + public final void verifyBeanNameSet() { + assertEquals("The bean name of this test instance should have been set due to BeanNameAware semantics.", + getClass().getName(), this.beanName); + } + + @Test + public final void verifyAnnotationAutowiredFields() { + assertNull("The nonrequiredLong field should NOT have been autowired.", this.nonrequiredLong); + assertNotNull("The pet field should have been autowired.", this.pet); + assertEquals("Fido", this.pet.getName()); + } + + @Test + public final void verifyAnnotationAutowiredMethods() { + assertNotNull("The employee setter method should have been autowired.", this.employee); + assertEquals("John Smith", this.employee.getName()); + } + + @Test + public final void verifyResourceAnnotationWiredFields() { + assertEquals("The foo field should have been wired via @Resource.", "Foo", this.foo); + } + + @Test + public final void verifyResourceAnnotationWiredMethods() { + assertEquals("The bar method should have been wired via @Resource.", "Bar", this.bar); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerTests.java new file mode 100644 index 00000000000..aedd5ad4666 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerTests.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import org.junit.Test; + +import org.springframework.test.context.TestContextManager; + +/** + * @author Rick Evans + * @author Sam Brannen + * @since 2.5 + */ +public class SpringJUnit4ClassRunnerTests { + + @Test(expected = Exception.class) + public void checkThatExceptionsAreNotSilentlySwallowed() throws Exception { + SpringJUnit4ClassRunner runner = new SpringJUnit4ClassRunner(getClass()) { + + @Override + protected TestContextManager createTestContextManager(Class clazz) { + return new TestContextManager(clazz) { + + @Override + public void prepareTestInstance(Object testInstance) { + throw new RuntimeException("This RuntimeException should be caught and wrapped in an Exception."); + } + }; + } + }; + runner.createTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java new file mode 100644 index 00000000000..34b2e967511 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +import org.springframework.test.context.SpringRunnerContextCacheTests; + +/** + *

+ * JUnit 4 based test suite for tests involving {@link SpringJUnit4ClassRunner}, + * {@link SpringMethodRoadie}, and Spring's annotation-based test support. + *

+ *

+ * This test suite serves a dual purpose of verifying that tests run with + * {@link SpringJUnit4ClassRunner} can be used in conjunction with JUnit 4's + * {@link Suite} runner. + *

+ *

+ * Note that tests included in this suite will be executed at least twice if run + * from an automated build process, test runner, etc. that is configured to run + * tests based on a "*Tests.class" pattern match. + *

+ * + * @author Sam Brannen + * @since 2.5 + */ +@RunWith(Suite.class) +// Note: the following 'multi-line' layout is for enhanced code readability. +@SuiteClasses( { + +StandardJUnit4FeaturesTests.class, + +StandardJUnit4FeaturesSpringRunnerTests.class, + +RepeatedSpringMethodRoadieTests.class, + +EnabledAndIgnoredSpringRunnerTests.class, + +HardCodedProfileValueSourceSpringRunnerTests.class, + +SpringJUnit4ClassRunnerAppCtxTests.class, + +ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests.class, + +AbsolutePathSpringJUnit4ClassRunnerAppCtxTests.class, + +RelativePathSpringJUnit4ClassRunnerAppCtxTests.class, + +MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests.class, + +InheritedConfigSpringJUnit4ClassRunnerAppCtxTests.class, + +PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests.class, + +SpringRunnerContextCacheTests.class, + +ParameterizedDependencyInjectionTests.class, + +ClassLevelTransactionalSpringRunnerTests.class, + +MethodLevelTransactionalSpringRunnerTests.class, + +DefaultRollbackTrueTransactionalSpringRunnerTests.class, + +DefaultRollbackFalseTransactionalSpringRunnerTests.class, + +RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests.class, + +RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests.class, + +BeforeAndAfterTransactionAnnotationTests.class, + +TimedTransactionalSpringRunnerTests.class + +}) +public class SpringJUnit4SuiteTests { + /* this test case is comprised completely of tests loaded as a suite. */ +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/StandardJUnit4FeaturesSpringRunnerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/StandardJUnit4FeaturesSpringRunnerTests.java new file mode 100644 index 00000000000..4dd270ca7c8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/StandardJUnit4FeaturesSpringRunnerTests.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import org.junit.runner.RunWith; + +import org.springframework.test.context.TestExecutionListeners; + +/** + *

+ * Simple unit test to verify that {@link SpringJUnit4ClassRunner} does not + * hinder correct functionality of standard JUnit 4.4+ testing features. + *

+ *

+ * Note that {@link TestExecutionListeners @TestExecutionListeners} is + * explicitly configured with an empty list, thus disabling all default + * listeners. + *

+ * + * @author Sam Brannen + * @since 2.5 + * @see StandardJUnit4FeaturesTests + */ +@RunWith(SpringJUnit4ClassRunner.class) +@TestExecutionListeners({}) +public class StandardJUnit4FeaturesSpringRunnerTests extends StandardJUnit4FeaturesTests { + + /* All tests are in the parent class... */ + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/StandardJUnit4FeaturesTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/StandardJUnit4FeaturesTests.java new file mode 100644 index 00000000000..3fd0aac69a9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/StandardJUnit4FeaturesTests.java @@ -0,0 +1,108 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import java.util.ArrayList; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +/** + * Simple unit test to verify the expected functionality of standard JUnit 4.4+ + * testing features. + *

+ * Currently testing: {@link Test @Test} (including expected exceptions and + * timeouts), {@link BeforeClass @BeforeClass}, {@link Before @Before}, and + * assumptions. + *

+ *

+ * Due to the fact that JUnit does not guarantee a particular ordering of test + * method execution, the following are currently not tested: + * {@link org.junit.AfterClass @AfterClass} and {@link org.junit.After @After}. + *

+ * + * @author Sam Brannen + * @since 2.5 + * @see StandardJUnit4FeaturesSpringRunnerTests + */ +public class StandardJUnit4FeaturesTests { + + private static int staticBeforeCounter = 0; + + + @BeforeClass + public static void incrementStaticBeforeCounter() { + StandardJUnit4FeaturesTests.staticBeforeCounter++; + } + + + private int beforeCounter = 0; + + + @Test + @Ignore + public void alwaysFailsButShouldBeIgnored() { + fail("The body of an ignored test should never be executed!"); + } + + @Test + public void alwaysSucceeds() { + assertTrue(true); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void expectingAnIndexOutOfBoundsException() { + new ArrayList().get(1); + } + + @Test + public void failedAssumptionShouldPrecludeImminentFailure() { + assumeTrue(false); + fail("A failed assumption should preclude imminent failure!"); + } + + @Before + public void incrementBeforeCounter() { + this.beforeCounter++; + } + + @Test(timeout = 10000) + public void noOpShouldNotTimeOut() { + /* no-op */ + } + + @Test + public void verifyBeforeAnnotation() { + assertEquals(1, this.beforeCounter); + } + + @Test + public void verifyBeforeClassAnnotation() { + // Instead of testing for equality to 1, we just assert that the value + // was incremented at least once, since this test class may serve as a + // parent class to other tests in a suite, etc. + assertTrue(StandardJUnit4FeaturesTests.staticBeforeCounter > 0); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/TimedTransactionalSpringRunnerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/TimedTransactionalSpringRunnerTests.java new file mode 100644 index 00000000000..e9df6b3ceae --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/TimedTransactionalSpringRunnerTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4; + +import static org.springframework.test.transaction.TransactionTestUtils.assertInTransaction; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.test.annotation.NotTransactional; +import org.springframework.test.annotation.Repeat; +import org.springframework.test.annotation.Timed; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.transaction.annotation.Transactional; + +/** + * JUnit 4 based unit test which verifies support of Spring's + * {@link Transactional @Transactional} and + * {@link NotTransactional @NotTransactional} annotations in conjunction with + * {@link Timed @Timed} and JUnit 4's {@link Test#timeout() timeout} attribute. + * + * @author Sam Brannen + * @since 2.5 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = {"transactionalTests-context.xml"}) +@Transactional +public class TimedTransactionalSpringRunnerTests { + + @Test + @Timed(millis = 10000) + @Repeat(5) + public void transactionalWithSpringTimeout() { + assertInTransaction(true); + } + + @Test(timeout = 10000) + @Repeat(5) + public void transactionalWithJUnitTimeout() { + assertInTransaction(true); + } + + @Test + @NotTransactional + @Timed(millis = 10000) + @Repeat(5) + public void notTransactionalWithSpringTimeout() { + assertInTransaction(false); + } + + @Test(timeout = 10000) + @NotTransactional + @Repeat(5) + public void notTransactionalWithJUnitTimeout() { + assertInTransaction(false); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/BeanOverridingDefaultLocationsInheritedTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/BeanOverridingDefaultLocationsInheritedTests-context.xml new file mode 100644 index 00000000000..55a4cff1e8a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/BeanOverridingDefaultLocationsInheritedTests-context.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/BeanOverridingDefaultLocationsInheritedTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/BeanOverridingDefaultLocationsInheritedTests.java new file mode 100644 index 00000000000..0c3b56be2db --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/BeanOverridingDefaultLocationsInheritedTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4.spr3896; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +import org.springframework.test.context.ContextConfiguration; + +/** + *

+ * JUnit 4 based unit test for verifying support for the + * {@link ContextConfiguration#inheritLocations() inheritLocations} flag of + * {@link ContextConfiguration @ContextConfiguration} indirectly proposed in SPR-3896. + *

+ * + * @author Sam Brannen + * @since 2.5 + */ +@ContextConfiguration +public class BeanOverridingDefaultLocationsInheritedTests extends DefaultLocationsBaseTests { + + @Test + @Override + public void verifyEmployeeSetFromBaseContextConfig() { + assertNotNull("The employee should have been autowired.", this.employee); + assertEquals("The employee bean should have been overridden.", "Yoda", this.employee.getName()); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/BeanOverridingExplicitLocationsInheritedTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/BeanOverridingExplicitLocationsInheritedTests.java new file mode 100644 index 00000000000..3d29fb51596 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/BeanOverridingExplicitLocationsInheritedTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4.spr3896; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +import org.springframework.test.context.ContextConfiguration; + +/** + *

+ * JUnit 4 based unit test for verifying support for the + * {@link ContextConfiguration#inheritLocations() inheritLocations} flag of + * {@link ContextConfiguration @ContextConfiguration} indirectly proposed in SPR-3896. + *

+ * + * @author Sam Brannen + * @since 2.5 + */ +@ContextConfiguration(locations = { "BeanOverridingDefaultLocationsInheritedTests-context.xml" }) +public class BeanOverridingExplicitLocationsInheritedTests extends ExplicitLocationsBaseTests { + + @Test + @Override + public void verifyEmployeeSetFromBaseContextConfig() { + assertNotNull("The employee should have been autowired.", this.employee); + assertEquals("The employee bean should have been overridden.", "Yoda", this.employee.getName()); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsBaseTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsBaseTests-context.xml new file mode 100644 index 00000000000..2f6eda6962f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsBaseTests-context.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsBaseTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsBaseTests.java new file mode 100644 index 00000000000..b5aafb6af22 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsBaseTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4.spr3896; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.Employee; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; + +/** + *

+ * JUnit 4 based unit test for verifying support for the + * {@link ContextConfiguration#inheritLocations() inheritLocations} flag of + * {@link ContextConfiguration @ContextConfiguration} indirectly proposed in SPR-3896. + *

+ * + * @author Sam Brannen + * @since 2.5 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class }) +public class DefaultLocationsBaseTests { + + @Autowired + protected Employee employee; + + + @Test + public void verifyEmployeeSetFromBaseContextConfig() { + assertNotNull("The employee should have been autowired.", this.employee); + assertEquals("John Smith", this.employee.getName()); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsInheritedTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsInheritedTests-context.xml new file mode 100644 index 00000000000..cb75b8accd4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsInheritedTests-context.xml @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsInheritedTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsInheritedTests.java new file mode 100644 index 00000000000..115977b17a8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/DefaultLocationsInheritedTests.java @@ -0,0 +1,52 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4.spr3896; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +import org.springframework.beans.Pet; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; + +/** + *

+ * JUnit 4 based unit test for verifying support for the + * {@link ContextConfiguration#inheritLocations() inheritLocations} flag of + * {@link ContextConfiguration @ContextConfiguration} indirectly proposed in SPR-3896. + *

+ * + * @author Sam Brannen + * @since 2.5 + */ +@ContextConfiguration +public class DefaultLocationsInheritedTests extends DefaultLocationsBaseTests { + + @Autowired + private Pet pet; + + + @Test + public void verifyPetSetFromExtendedContextConfig() { + assertNotNull("The pet should have been autowired.", this.pet); + assertEquals("Fido", this.pet.getName()); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/ExplicitLocationsBaseTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/ExplicitLocationsBaseTests.java new file mode 100644 index 00000000000..40818996b9b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/ExplicitLocationsBaseTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4.spr3896; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.Employee; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; + +/** + *

+ * JUnit 4 based unit test for verifying support for the + * {@link ContextConfiguration#inheritLocations() inheritLocations} flag of + * {@link ContextConfiguration @ContextConfiguration} indirectly proposed in SPR-3896. + *

+ * + * @author Sam Brannen + * @since 2.5 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "DefaultLocationsBaseTests-context.xml" }) +@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class }) +public class ExplicitLocationsBaseTests { + + @Autowired + protected Employee employee; + + + @Test + public void verifyEmployeeSetFromBaseContextConfig() { + assertNotNull("The employee should have been autowired.", this.employee); + assertEquals("John Smith", this.employee.getName()); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/ExplicitLocationsInheritedTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/ExplicitLocationsInheritedTests.java new file mode 100644 index 00000000000..a82908d177b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/ExplicitLocationsInheritedTests.java @@ -0,0 +1,52 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4.spr3896; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +import org.springframework.beans.Pet; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; + +/** + *

+ * JUnit 4 based unit test for verifying support for the + * {@link ContextConfiguration#inheritLocations() inheritLocations} flag of + * {@link ContextConfiguration @ContextConfiguration} indirectly proposed in SPR-3896. + *

+ * + * @author Sam Brannen + * @since 2.5 + */ +@ContextConfiguration(locations = { "DefaultLocationsInheritedTests-context.xml" }) +public class ExplicitLocationsInheritedTests extends ExplicitLocationsBaseTests { + + @Autowired + private Pet pet; + + + @Test + public void verifyPetSetFromExtendedContextConfig() { + assertNotNull("The pet should have been autowired.", this.pet); + assertEquals("Fido", this.pet.getName()); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/Spr3896SuiteTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/Spr3896SuiteTests.java new file mode 100644 index 00000000000..b6abcae4739 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/spr3896/Spr3896SuiteTests.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4.spr3896; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +/** + *

+ * JUnit 4 based test suite for functionality proposed in SPR-3896. + *

+ * + * @author Sam Brannen + * @since 2.5 + */ +@RunWith(Suite.class) +// Note: the following 'multi-line' layout is for enhanced code readability. +@SuiteClasses( { + +DefaultLocationsBaseTests.class, + +DefaultLocationsInheritedTests.class, + +ExplicitLocationsBaseTests.class, + +ExplicitLocationsInheritedTests.class, + +BeanOverridingDefaultLocationsInheritedTests.class, + +BeanOverridingExplicitLocationsInheritedTests.class + +}) +public class Spr3896SuiteTests { +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/transactionalTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/transactionalTests-context.xml new file mode 100644 index 00000000000..d84211548d3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/junit4/transactionalTests-context.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/support/CustomizedGenericXmlContextLoaderTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/support/CustomizedGenericXmlContextLoaderTests-context.xml new file mode 100644 index 00000000000..a057012802b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/support/CustomizedGenericXmlContextLoaderTests-context.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/support/CustomizedGenericXmlContextLoaderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/support/CustomizedGenericXmlContextLoaderTests.java new file mode 100644 index 00000000000..a07d1d30aa2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/support/CustomizedGenericXmlContextLoaderTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.support; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import org.junit.Test; + +import org.springframework.context.support.GenericApplicationContext; + +/** + * Unit test which verifies that extensions of + * {@link AbstractGenericContextLoader} are able to customize the + * newly created ApplicationContext. Specifically, this test + * addresses the issues raised in SPR-4008: Supply an opportunity to customize context + * before calling refresh in ContextLoaders. + * + * @author Sam Brannen + * @since 2.5 + */ +public class CustomizedGenericXmlContextLoaderTests { + + @Test + public void customizeContext() throws Exception { + + final StringBuilder builder = new StringBuilder(); + final String expectedContents = "customizeContext() was called"; + + new GenericXmlContextLoader() { + + @Override + protected void customizeContext(GenericApplicationContext context) { + assertFalse("The context should not yet have been refreshed.", context.isActive()); + builder.append(expectedContents); + } + }.loadContext("classpath:/org/springframework/test/context/support/CustomizedGenericXmlContextLoaderTests-context.xml"); + + assertEquals("customizeContext() should have been called.", expectedContents, builder.toString()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/support/GenericXmlContextLoaderResourceLocationsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/support/GenericXmlContextLoaderResourceLocationsTests.java new file mode 100644 index 00000000000..1813dc90d73 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/support/GenericXmlContextLoaderResourceLocationsTests.java @@ -0,0 +1,137 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.support; + +import static org.junit.Assert.assertArrayEquals; + +import java.util.Arrays; +import java.util.Collection; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.ContextLoader; +import org.springframework.util.ObjectUtils; + +/** + * JUnit 4 based unit test which verifies proper + * {@link ContextLoader#processLocations(Class,String...) processing} of + * resource locations by a {@link GenericXmlContextLoader} + * configured via {@link ContextConfiguration @ContextConfiguration}. + * Specifically, this test addresses the issues raised in SPR-3949: + * ContextConfiguration annotation should accept not only classpath resources. + * + * @author Sam Brannen + * @since 2.5 + */ +@RunWith(Parameterized.class) +public class GenericXmlContextLoaderResourceLocationsTests { + + private static final Log logger = LogFactory.getLog(GenericXmlContextLoaderResourceLocationsTests.class); + + protected final Class testClass; + protected final String[] expectedLocations; + + + public GenericXmlContextLoaderResourceLocationsTests(final Class testClass, final String[] expectedLocations) { + this.testClass = testClass; + this.expectedLocations = expectedLocations; + } + + @Parameters + public static Collection contextConfigurationLocationsData() { + return Arrays.asList(new Object[][] { + + { + ClasspathDefaultLocationsTest.class, + new String[] { "classpath:/org/springframework/test/context/support/GenericXmlContextLoaderResourceLocationsTests$ClasspathDefaultLocationsTest-context.xml" } }, + + { + ImplicitClasspathLocationsTest.class, + new String[] { "classpath:/org/springframework/test/context/support/context1.xml", + "classpath:/org/springframework/test/context/support/context2.xml" } }, + + { ExplicitClasspathLocationsTest.class, new String[] { "classpath:context.xml" } }, + + { ExplicitFileLocationsTest.class, new String[] { "file:/testing/directory/context.xml" } }, + + { ExplicitUrlLocationsTest.class, new String[] { "http://example.com/context.xml" } }, + + { + ExplicitMixedPathTypesLocationsTest.class, + new String[] { "classpath:/org/springframework/test/context/support/context1.xml", + "classpath:context2.xml", "classpath:/context3.xml", "file:/testing/directory/context.xml", + "http://example.com/context.xml" } } + + }); + } + + @Test + @SuppressWarnings("unchecked") + public void assertContextConfigurationLocations() throws Exception { + + final ContextConfiguration contextConfig = this.testClass.getAnnotation(ContextConfiguration.class); + final ContextLoader contextLoader = new GenericXmlContextLoader(); + final String[] configuredLocations = (String[]) AnnotationUtils.getValue(contextConfig, "locations"); + final String[] processedLocations = contextLoader.processLocations(this.testClass, configuredLocations); + + if (logger.isDebugEnabled()) { + logger.debug("----------------------------------------------------------------------"); + logger.debug("Configured locations: " + ObjectUtils.nullSafeToString(configuredLocations)); + logger.debug("Expected locations: " + ObjectUtils.nullSafeToString(this.expectedLocations)); + logger.debug("Processed locations: " + ObjectUtils.nullSafeToString(processedLocations)); + } + + assertArrayEquals("Verifying locations for test [" + this.testClass + "].", this.expectedLocations, + processedLocations); + } + + + @ContextConfiguration + private static class ClasspathDefaultLocationsTest { + } + + @ContextConfiguration(locations = { "context1.xml", "context2.xml" }) + private static class ImplicitClasspathLocationsTest { + } + + @ContextConfiguration(locations = { "classpath:context.xml" }) + private static class ExplicitClasspathLocationsTest { + } + + @ContextConfiguration(locations = { "file:/testing/directory/context.xml" }) + private static class ExplicitFileLocationsTest { + } + + @ContextConfiguration(locations = { "http://example.com/context.xml" }) + private static class ExplicitUrlLocationsTest { + } + + @ContextConfiguration(locations = { "context1.xml", "classpath:context2.xml", "/context3.xml", + "file:/testing/directory/context.xml", "http://example.com/context.xml" }) + private static class ExplicitMixedPathTypesLocationsTest { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/ConcreteTransactionalTestNGSpringContextTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/ConcreteTransactionalTestNGSpringContextTests-context.xml new file mode 100644 index 00000000000..037962cac89 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/ConcreteTransactionalTestNGSpringContextTests-context.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/ConcreteTransactionalTestNGSpringContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/ConcreteTransactionalTestNGSpringContextTests.java new file mode 100644 index 00000000000..7707e0f6355 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/ConcreteTransactionalTestNGSpringContextTests.java @@ -0,0 +1,291 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.testng; + +import static org.springframework.test.transaction.TransactionTestUtils.assertInTransaction; +import static org.springframework.test.transaction.TransactionTestUtils.inTransaction; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import javax.annotation.Resource; +import javax.sql.DataSource; + +import org.springframework.beans.Employee; +import org.springframework.beans.Pet; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.BadSqlGrammarException; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.test.annotation.NotTransactional; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.transaction.AfterTransaction; +import org.springframework.test.context.transaction.BeforeTransaction; +import org.springframework.test.jdbc.SimpleJdbcTestUtils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * Combined unit test for {@link AbstractTestNGSpringContextTests} and + * {@link AbstractTransactionalTestNGSpringContextTests}. + * + * @author Sam Brannen + * @since 2.5 + */ +@ContextConfiguration +public class ConcreteTransactionalTestNGSpringContextTests extends AbstractTransactionalTestNGSpringContextTests + implements BeanNameAware, InitializingBean { + + // ------------------------------------------------------------------------| + // --- CONSTANTS ----------------------------------------------------------| + // ------------------------------------------------------------------------| + + private static final String BOB = "bob"; + private static final String JANE = "jane"; + private static final String SUE = "sue"; + private static final String YODA = "yoda"; + + // ------------------------------------------------------------------------| + // --- STATIC VARIABLES ---------------------------------------------------| + // ------------------------------------------------------------------------| + + private static int numSetUpCalls = 0; + private static int numSetUpCallsInTransaction = 0; + private static int numTearDownCalls = 0; + private static int numTearDownCallsInTransaction = 0; + + // ------------------------------------------------------------------------| + // --- INSTANCE VARIABLES -------------------------------------------------| + // ------------------------------------------------------------------------| + + private boolean beanInitialized = false; + + private String beanName = "replace me with [" + getClass().getName() + "]"; + + private Employee employee; + + @Autowired + private Pet pet; + + @Autowired(required = false) + protected Long nonrequiredLong; + + @Resource() + protected String foo; + + protected String bar; + + + // ------------------------------------------------------------------------| + // --- STATIC METHODS -----------------------------------------------------| + // ------------------------------------------------------------------------| + + private static int clearPersonTable(SimpleJdbcTemplate simpleJdbcTemplate) { + return SimpleJdbcTestUtils.deleteFromTables(simpleJdbcTemplate, "person"); + } + + private static void createPersonTable(SimpleJdbcTemplate simpleJdbcTemplate) { + try { + simpleJdbcTemplate.update("CREATE TABLE person (name VARCHAR(20) NOT NULL, PRIMARY KEY(name))"); + } + catch (BadSqlGrammarException bsge) { + /* ignore */ + } + } + + private static int countRowsInPersonTable(SimpleJdbcTemplate simpleJdbcTemplate) { + return SimpleJdbcTestUtils.countRowsInTable(simpleJdbcTemplate, "person"); + } + + private static int addPerson(SimpleJdbcTemplate simpleJdbcTemplate, String name) { + return simpleJdbcTemplate.update("INSERT INTO person VALUES(?)", name); + } + + private static int deletePerson(SimpleJdbcTemplate simpleJdbcTemplate, String name) { + return simpleJdbcTemplate.update("DELETE FROM person WHERE name=?", name); + } + + // ------------------------------------------------------------------------| + // --- INSTANCE METHODS ---------------------------------------------------| + // ------------------------------------------------------------------------| + + public void afterPropertiesSet() throws Exception { + this.beanInitialized = true; + } + + public void setBeanName(String beanName) { + this.beanName = beanName; + } + + @Autowired + protected void setEmployee(Employee employee) { + this.employee = employee; + } + + @Resource + protected void setBar(String bar) { + this.bar = bar; + } + + // ------------------------------------------------------------------------| + + private void assertNumRowsInPersonTable(int expectedNumRows, String testState) { + assertEquals(countRowsInPersonTable(this.simpleJdbcTemplate), expectedNumRows, + "Verifying the number of rows in the person table (" + testState + ")."); + } + + private void assertAddPerson(final String name) { + assertEquals(addPerson(this.simpleJdbcTemplate, name), 1, "Adding '" + name + "'"); + } + + // ------------------------------------------------------------------------| + + @BeforeClass + public void beforeClass() { + numSetUpCalls = 0; + numSetUpCallsInTransaction = 0; + numTearDownCalls = 0; + numTearDownCallsInTransaction = 0; + } + + @AfterClass + public void afterClass() { + assertEquals(numSetUpCalls, 8, "Verifying number of calls to setUp()."); + assertEquals(numSetUpCallsInTransaction, 1, "Verifying number of calls to setUp() within a transaction."); + assertEquals(numTearDownCalls, 8, "Verifying number of calls to tearDown()."); + assertEquals(numTearDownCallsInTransaction, 1, "Verifying number of calls to tearDown() within a transaction."); + } + + @Test + @NotTransactional + public void verifyApplicationContextSet() { + assertInTransaction(false); + assertNotNull(super.applicationContext, + "The application context should have been set due to ApplicationContextAware semantics."); + Employee employeeBean = (Employee) super.applicationContext.getBean("employee"); + assertEquals(employeeBean.getName(), "John Smith", "Verifying employee's name."); + } + + @Test + @NotTransactional + public void verifyBeanInitialized() { + assertInTransaction(false); + assertTrue(this.beanInitialized, + "This test instance should have been initialized due to InitializingBean semantics."); + } + + @Test + @NotTransactional + public void verifyBeanNameSet() { + assertInTransaction(false); + assertEquals(this.beanName, getClass().getName(), + "The bean name of this test instance should have been set due to BeanNameAware semantics."); + } + + @Test + @NotTransactional + public void verifyAnnotationAutowiredFields() { + assertInTransaction(false); + assertNull(this.nonrequiredLong, "The nonrequiredLong field should NOT have been autowired."); + assertNotNull(this.pet, "The pet field should have been autowired."); + assertEquals(this.pet.getName(), "Fido", "Verifying pet's name."); + } + + @Test + @NotTransactional + public void verifyAnnotationAutowiredMethods() { + assertInTransaction(false); + assertNotNull(this.employee, "The setEmployee() method should have been autowired."); + assertEquals(this.employee.getName(), "John Smith", "Verifying employee's name."); + } + + @Test + @NotTransactional + public void verifyResourceAnnotationInjectedFields() { + assertInTransaction(false); + assertEquals(this.foo, "Foo", "The foo field should have been injected via @Resource."); + } + + @Test + @NotTransactional + public void verifyResourceAnnotationInjectedMethods() { + assertInTransaction(false); + assertEquals(this.bar, "Bar", "The setBar() method should have been injected via @Resource."); + } + + // ------------------------------------------------------------------------| + + @BeforeTransaction + public void beforeTransaction() { + assertNumRowsInPersonTable(1, "before a transactional test method"); + assertAddPerson(YODA); + } + + @BeforeMethod + public void setUp() throws Exception { + numSetUpCalls++; + if (inTransaction()) { + numSetUpCallsInTransaction++; + } + assertNumRowsInPersonTable((inTransaction() ? 2 : 1), "before a test method"); + } + + @Test + public void modifyTestDataWithinTransaction() { + assertInTransaction(true); + assertAddPerson(JANE); + assertAddPerson(SUE); + assertNumRowsInPersonTable(4, "in modifyTestDataWithinTransaction()"); + } + + @AfterMethod + public void tearDown() throws Exception { + numTearDownCalls++; + if (inTransaction()) { + numTearDownCallsInTransaction++; + } + assertNumRowsInPersonTable((inTransaction() ? 4 : 1), "after a test method"); + } + + @AfterTransaction + public void afterTransaction() { + assertEquals(deletePerson(this.simpleJdbcTemplate, YODA), 1, "Deleting yoda"); + assertNumRowsInPersonTable(1, "after a transactional test method"); + } + + + // ------------------------------------------------------------------------| + // --- TYPES --------------------------------------------------------------| + // ------------------------------------------------------------------------| + + public static class DatabaseSetup { + + @Autowired + void setDataSource(DataSource dataSource) { + SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); + createPersonTable(simpleJdbcTemplate); + clearPersonTable(simpleJdbcTemplate); + addPerson(simpleJdbcTemplate, BOB); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/DirtiesContextTransactionalTestNGSpringContextTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/DirtiesContextTransactionalTestNGSpringContextTests-context.xml new file mode 100644 index 00000000000..3c4fc976b8e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/DirtiesContextTransactionalTestNGSpringContextTests-context.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/DirtiesContextTransactionalTestNGSpringContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/DirtiesContextTransactionalTestNGSpringContextTests.java new file mode 100644 index 00000000000..989f9c29f6a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/DirtiesContextTransactionalTestNGSpringContextTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.testng; + +import static org.springframework.test.transaction.TransactionTestUtils.assertInTransaction; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNotSame; +import static org.testng.Assert.assertSame; + +import org.springframework.context.ApplicationContext; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestContextManager; +import org.testng.annotations.Test; + +/** + *

+ * TestNG based unit test to assess the claim in SPR-3880 that a "context marked dirty using + * {@link DirtiesContext @DirtiesContext} in [a] TestNG based test is not + * reloaded in subsequent tests". + *

+ *

+ * After careful analysis, it turns out that the {@link ApplicationContext} was + * in fact reloaded; however, due to how the test instance was instrumented with + * the {@link TestContextManager} in {@link AbstractTestNGSpringContextTests}, + * dependency injection was not being performed on the test instance between + * individual tests. DirtiesContextTransactionalTestNGSpringContextTests + * therefore verifies the expected behavior and correct semantics. + *

+ * + * @author Sam Brannen + * @since 2.5 + */ +@ContextConfiguration +public class DirtiesContextTransactionalTestNGSpringContextTests extends AbstractTransactionalTestNGSpringContextTests { + + private ApplicationContext dirtiedApplicationContext; + + + private void performCommonAssertions() { + assertInTransaction(true); + assertNotNull(super.applicationContext, + "The application context should have been set due to ApplicationContextAware semantics."); + assertNotNull(super.simpleJdbcTemplate, + "The SimpleJdbcTemplate should have been created in setDataSource() via DI for the DataSource."); + } + + @Test + @DirtiesContext + public void dirtyContext() { + performCommonAssertions(); + this.dirtiedApplicationContext = super.applicationContext; + } + + @Test(dependsOnMethods = { "dirtyContext" }) + public void verifyContextWasDirtied() { + performCommonAssertions(); + assertNotSame(super.applicationContext, this.dirtiedApplicationContext, + "The application context should have been 'dirtied'."); + this.dirtiedApplicationContext = super.applicationContext; + } + + @Test(dependsOnMethods = { "verifyContextWasDirtied" }) + public void verifyContextWasNotDirtied() { + assertSame(this.applicationContext, this.dirtiedApplicationContext, + "The application context should NOT have been 'dirtied'."); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/FailingBeforeAndAfterMethodsTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/FailingBeforeAndAfterMethodsTests-context.xml new file mode 100644 index 00000000000..3c4fc976b8e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/FailingBeforeAndAfterMethodsTests-context.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/FailingBeforeAndAfterMethodsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/FailingBeforeAndAfterMethodsTests.java new file mode 100644 index 00000000000..89fb4ffed85 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/context/testng/FailingBeforeAndAfterMethodsTests.java @@ -0,0 +1,207 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.testng; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.testng.ITestContext; +import org.testng.ITestListener; +import org.testng.ITestResult; +import org.testng.TestNG; + +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestContext; +import org.springframework.test.context.TestExecutionListener; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.support.AbstractTestExecutionListener; +import org.springframework.test.context.transaction.AfterTransaction; +import org.springframework.test.context.transaction.BeforeTransaction; + +/** + *

+ * JUnit 4 based unit test for verifying that 'before' and 'after' + * methods of {@link TestExecutionListener TestExecutionListeners} as well as + * {@link BeforeTransaction @BeforeTransaction} and + * {@link AfterTransaction @AfterTransaction} methods can fail a test in a + * TestNG environment, as requested in SPR-3960. + *

+ * + * @author Sam Brannen + * @since 2.5 + */ +@RunWith(Parameterized.class) +public class FailingBeforeAndAfterMethodsTests { + + protected final Class clazz; + protected final int expectedTestStartCount; + protected final int expectedTestSuccessCount; + protected final int expectedFailureCount; + protected final int expectedFailedConfigurationsCount; + + + public FailingBeforeAndAfterMethodsTests(final Class clazz, final int expectedTestStartCount, + final int expectedTestSuccessCount, final int expectedFailureCount, + final int expectedFailedConfigurationsCount) { + this.clazz = clazz; + this.expectedTestStartCount = expectedTestStartCount; + this.expectedTestSuccessCount = expectedTestSuccessCount; + this.expectedFailureCount = expectedFailureCount; + this.expectedFailedConfigurationsCount = expectedFailedConfigurationsCount; + } + + @Parameters + public static Collection testData() { + return Arrays.asList(new Object[][] { + + { AlwaysFailingBeforeTestMethodTestCase.class, 1, 0, 0, 1 }, + + { AlwaysFailingAfterTestMethodTestCase.class, 1, 1, 0, 1 }, + + { FailingBeforeTransactionalTestCase.class, 1, 0, 0, 1 }, + + { FailingAfterTransactionalTestCase.class, 1, 1, 0, 1 } + + }); + } + + @Test + public void runTestAndAssertCounters() throws Exception { + final FailureTrackingTestListener listener = new FailureTrackingTestListener(); + final TestNG testNG = new TestNG(); + testNG.addListener(listener); + testNG.setTestClasses(new Class[] { this.clazz }); + testNG.setVerbose(0); + testNG.run(); + + assertEquals("Verifying number of test starts for test class [" + this.clazz + "].", + this.expectedTestStartCount, listener.testStartCount); + assertEquals("Verifying number of successful tests for test class [" + this.clazz + "].", + this.expectedTestSuccessCount, listener.testSuccessCount); + assertEquals("Verifying number of failures for test class [" + this.clazz + "].", this.expectedFailureCount, + listener.testFailureCount); + assertEquals("Verifying number of failed configurations for test class [" + this.clazz + "].", + this.expectedFailedConfigurationsCount, listener.failedConfigurationsCount); + } + + + static class FailureTrackingTestListener implements ITestListener { + + int testStartCount = 0; + int testSuccessCount = 0; + int testFailureCount = 0; + int failedConfigurationsCount = 0; + + + public void onFinish(ITestContext testContext) { + this.failedConfigurationsCount += testContext.getFailedConfigurations().size(); + } + + public void onStart(ITestContext testContext) { + } + + public void onTestFailedButWithinSuccessPercentage(ITestResult testResult) { + } + + public void onTestFailure(ITestResult testResult) { + this.testFailureCount++; + } + + public void onTestSkipped(ITestResult testResult) { + } + + public void onTestStart(ITestResult testResult) { + this.testStartCount++; + } + + public void onTestSuccess(ITestResult testResult) { + this.testSuccessCount++; + } + } + + + static class AlwaysFailingBeforeTestMethodTestExecutionListener extends AbstractTestExecutionListener { + + @Override + public void beforeTestMethod(TestContext testContext) { + org.testng.Assert.fail("always failing beforeTestMethod()"); + } + } + + static class AlwaysFailingAfterTestMethodTestExecutionListener extends AbstractTestExecutionListener { + + @Override + public void afterTestMethod(TestContext testContext) { + org.testng.Assert.fail("always failing afterTestMethod()"); + } + } + + + @TestExecutionListeners(value = { AlwaysFailingBeforeTestMethodTestExecutionListener.class }, inheritListeners = false) + public static class AlwaysFailingBeforeTestMethodTestCase extends AbstractTestNGSpringContextTests { + + @org.testng.annotations.Test + public void testNothing() { + } + } + + + @TestExecutionListeners(value = { AlwaysFailingAfterTestMethodTestExecutionListener.class }, inheritListeners = false) + public static class AlwaysFailingAfterTestMethodTestCase extends AbstractTestNGSpringContextTests { + + @org.testng.annotations.Test + public void testNothing() { + } + } + + + @ContextConfiguration(locations = { "FailingBeforeAndAfterMethodsTests-context.xml" }) + public static class FailingBeforeTransactionalTestCase extends AbstractTransactionalTestNGSpringContextTests { + + @org.testng.annotations.Test + public void testNothing() { + } + + @BeforeTransaction + public void beforeTransaction() { + org.testng.Assert.fail("always failing beforeTransaction()"); + } + } + + + @ContextConfiguration(locations = { "FailingBeforeAndAfterMethodsTests-context.xml" }) + public static class FailingAfterTransactionalTestCase extends AbstractTransactionalTestNGSpringContextTests { + + @org.testng.annotations.Test + public void testNothing() { + } + + @AfterTransaction + public void afterTransaction() { + org.testng.Assert.fail("always failing afterTransaction()"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java new file mode 100644 index 00000000000..64fb2e77a28 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java @@ -0,0 +1,508 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.annotation; + +import java.io.IOException; +import java.io.Serializable; +import java.lang.reflect.Method; + +import javax.ejb.TransactionAttributeType; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.Advised; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.transaction.CallCountingTransactionManager; +import org.springframework.transaction.interceptor.NoRollbackRuleAttribute; +import org.springframework.transaction.interceptor.RollbackRuleAttribute; +import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute; +import org.springframework.transaction.interceptor.TransactionAttribute; +import org.springframework.transaction.interceptor.TransactionInterceptor; +import org.springframework.util.SerializationTestUtils; + +/** + * @author Colin Sampaleanu + * @author Juergen Hoeller + */ +public class AnnotationTransactionAttributeSourceTests extends TestCase { + + public void testSerializable() throws Exception { + TestBean1 tb = new TestBean1(); + CallCountingTransactionManager ptm = new CallCountingTransactionManager(); + AnnotationTransactionAttributeSource tas = new AnnotationTransactionAttributeSource(); + TransactionInterceptor ti = new TransactionInterceptor(ptm, tas); + + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.setInterfaces(new Class[] {ITestBean.class}); + proxyFactory.addAdvice(ti); + proxyFactory.setTarget(tb); + ITestBean proxy = (ITestBean) proxyFactory.getProxy(); + proxy.getAge(); + assertEquals(1, ptm.commits); + + ITestBean serializedProxy = (ITestBean) SerializationTestUtils.serializeAndDeserialize(proxy); + serializedProxy.getAge(); + Advised advised = (Advised) serializedProxy; + TransactionInterceptor serializedTi = (TransactionInterceptor) advised.getAdvisors()[0].getAdvice(); + CallCountingTransactionManager serializedPtm = + (CallCountingTransactionManager) serializedTi.getTransactionManager(); + assertEquals(2, serializedPtm.commits); + } + + public void testNullOrEmpty() throws Exception { + Method method = Empty.class.getMethod("getAge", (Class[]) null); + + AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); + assertNull(atas.getTransactionAttribute(method, null)); + + // Try again in case of caching + assertNull(atas.getTransactionAttribute(method, null)); + } + + /** + * Test the important case where the invocation is on a proxied interface method + * but the attribute is defined on the target class. + */ + public void testTransactionAttributeDeclaredOnClassMethod() throws Exception { + Method classMethod = ITestBean.class.getMethod("getAge", (Class[]) null); + + AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); + TransactionAttribute actual = atas.getTransactionAttribute(classMethod, TestBean1.class); + + RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); + rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); + assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); + } + + /** + * Test case where attribute is on the interface method. + */ + public void testTransactionAttributeDeclaredOnInterfaceMethodOnly() throws Exception { + Method interfaceMethod = ITestBean2.class.getMethod("getAge", (Class[]) null); + + AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); + TransactionAttribute actual = atas.getTransactionAttribute(interfaceMethod, TestBean2.class); + + RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); + assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); + } + + /** + * Test that when an attribute exists on both class and interface, class takes precedence. + */ + public void testTransactionAttributeOnTargetClassMethodOverridesAttributeOnInterfaceMethod() throws Exception { + Method interfaceMethod = ITestBean3.class.getMethod("getAge", (Class[]) null); + Method interfaceMethod2 = ITestBean3.class.getMethod("getName", (Class[]) null); + + AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); + TransactionAttribute actual = atas.getTransactionAttribute(interfaceMethod, TestBean3.class); + assertEquals(TransactionAttribute.PROPAGATION_REQUIRES_NEW, actual.getPropagationBehavior()); + assertEquals(TransactionAttribute.ISOLATION_REPEATABLE_READ, actual.getIsolationLevel()); + assertEquals(5, actual.getTimeout()); + assertTrue(actual.isReadOnly()); + + RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); + rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); + rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); + assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); + + TransactionAttribute actual2 = atas.getTransactionAttribute(interfaceMethod2, TestBean3.class); + assertEquals(TransactionAttribute.PROPAGATION_REQUIRED, actual2.getPropagationBehavior()); + } + + public void testRollbackRulesAreApplied() throws Exception { + Method method = TestBean3.class.getMethod("getAge", (Class[]) null); + + AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); + TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean3.class); + + RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); + rbta.getRollbackRules().add(new RollbackRuleAttribute("java.lang.Exception")); + rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); + + assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); + assertTrue(actual.rollbackOn(new Exception())); + assertFalse(actual.rollbackOn(new IOException())); + + actual = atas.getTransactionAttribute(method, method.getDeclaringClass()); + + rbta = new RuleBasedTransactionAttribute(); + rbta.getRollbackRules().add(new RollbackRuleAttribute("java.lang.Exception")); + rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); + + assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); + assertTrue(actual.rollbackOn(new Exception())); + assertFalse(actual.rollbackOn(new IOException())); + } + + /** + * Test that transaction attribute is inherited from class + * if not specified on method. + */ + public void testDefaultsToClassTransactionAttribute() throws Exception { + Method method = TestBean4.class.getMethod("getAge", (Class[]) null); + + AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); + TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean4.class); + + RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); + rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); + rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); + assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); + } + + public void testTransactionAttributeDeclaredOnClassMethodWithEjb3() throws Exception { + Method getAgeMethod = ITestBean.class.getMethod("getAge", (Class[]) null); + Method getNameMethod = ITestBean.class.getMethod("getName", (Class[]) null); + + AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); + TransactionAttribute getAgeAttr = atas.getTransactionAttribute(getAgeMethod, Ejb3AnnotatedBean1.class); + assertEquals(TransactionAttribute.PROPAGATION_REQUIRED, getAgeAttr.getPropagationBehavior()); + TransactionAttribute getNameAttr = atas.getTransactionAttribute(getNameMethod, Ejb3AnnotatedBean1.class); + assertEquals(TransactionAttribute.PROPAGATION_SUPPORTS, getNameAttr.getPropagationBehavior()); + } + + public void testTransactionAttributeDeclaredOnClassWithEjb3() throws Exception { + Method getAgeMethod = ITestBean.class.getMethod("getAge", (Class[]) null); + Method getNameMethod = ITestBean.class.getMethod("getName", (Class[]) null); + + AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); + TransactionAttribute getAgeAttr = atas.getTransactionAttribute(getAgeMethod, Ejb3AnnotatedBean2.class); + assertEquals(TransactionAttribute.PROPAGATION_REQUIRED, getAgeAttr.getPropagationBehavior()); + TransactionAttribute getNameAttr = atas.getTransactionAttribute(getNameMethod, Ejb3AnnotatedBean2.class); + assertEquals(TransactionAttribute.PROPAGATION_SUPPORTS, getNameAttr.getPropagationBehavior()); + } + + public void testTransactionAttributeDeclaredOnInterfaceWithEjb3() throws Exception { + Method getAgeMethod = ITestEjb.class.getMethod("getAge", (Class[]) null); + Method getNameMethod = ITestEjb.class.getMethod("getName", (Class[]) null); + + AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); + TransactionAttribute getAgeAttr = atas.getTransactionAttribute(getAgeMethod, Ejb3AnnotatedBean3.class); + assertEquals(TransactionAttribute.PROPAGATION_REQUIRED, getAgeAttr.getPropagationBehavior()); + TransactionAttribute getNameAttr = atas.getTransactionAttribute(getNameMethod, Ejb3AnnotatedBean3.class); + assertEquals(TransactionAttribute.PROPAGATION_SUPPORTS, getNameAttr.getPropagationBehavior()); + } + + + public interface ITestBean { + + int getAge(); + + void setAge(int age); + + String getName(); + + void setName(String name); + } + + + public interface ITestBean2 { + + @Transactional + int getAge(); + + void setAge(int age); + + String getName(); + + void setName(String name); + } + + + @Transactional + public interface ITestBean3 { + + int getAge(); + + void setAge(int age); + + String getName(); + + void setName(String name); + } + + + public static class Empty implements ITestBean { + + private String name; + + private int age; + + public Empty() { + } + + public Empty(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + } + + + public static class TestBean1 implements ITestBean, Serializable { + + private String name; + + private int age; + + public TestBean1() { + } + + public TestBean1(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Transactional(rollbackFor=Exception.class) + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + } + + + public static class TestBean2 implements ITestBean2 { + + private String name; + + private int age; + + public TestBean2() { + } + + public TestBean2(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + } + + + public static class TestBean3 implements ITestBean3 { + + private String name; + + private int age; + + public TestBean3() { + } + + public TestBean3(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.REPEATABLE_READ, timeout=5, + readOnly=true, rollbackFor=Exception.class, noRollbackFor={IOException.class}) + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + } + + + @Transactional(rollbackFor=Exception.class, noRollbackFor={IOException.class}) + public static class TestBean4 implements ITestBean3 { + + private String name; + + private int age; + + public TestBean4() { + } + + public TestBean4(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + } + + + public static interface Foo { + + void doSomething(T theArgument); + } + + + public static class MyFoo implements Foo { + + @Transactional + public void doSomething(String theArgument) { + System.out.println(theArgument); + } + } + + + public static class Ejb3AnnotatedBean1 implements ITestBean { + + private String name; + + private int age; + + @javax.ejb.TransactionAttribute(TransactionAttributeType.SUPPORTS) + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @javax.ejb.TransactionAttribute + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + } + + + @javax.ejb.TransactionAttribute(TransactionAttributeType.SUPPORTS) + public static class Ejb3AnnotatedBean2 implements ITestBean { + + private String name; + + private int age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @javax.ejb.TransactionAttribute + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + } + + + @javax.ejb.TransactionAttribute(TransactionAttributeType.SUPPORTS) + public interface ITestEjb { + + @javax.ejb.TransactionAttribute + int getAge(); + + void setAge(int age); + + String getName(); + + void setName(String name); + } + + + public static class Ejb3AnnotatedBean3 implements ITestEjb { + + private String name; + + private int age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionInterceptorTests.java new file mode 100644 index 00000000000..608512aefa0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionInterceptorTests.java @@ -0,0 +1,374 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.annotation; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.transaction.CallCountingTransactionManager; +import org.springframework.transaction.interceptor.TransactionInterceptor; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class AnnotationTransactionInterceptorTests extends TestCase { + + private CallCountingTransactionManager ptm; + + private AnnotationTransactionAttributeSource source; + + private TransactionInterceptor ti; + + + public void setUp() { + this.ptm = new CallCountingTransactionManager(); + this.source = new AnnotationTransactionAttributeSource(); + this.ti = new TransactionInterceptor(this.ptm, this.source); + } + + + public void testClassLevelOnly() { + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.setTarget(new TestClassLevelOnly()); + proxyFactory.addAdvice(this.ti); + + TestClassLevelOnly proxy = (TestClassLevelOnly) proxyFactory.getProxy(); + + proxy.doSomething(); + assertGetTransactionAndCommitCount(1); + + proxy.doSomethingElse(); + assertGetTransactionAndCommitCount(2); + + proxy.doSomething(); + assertGetTransactionAndCommitCount(3); + + proxy.doSomethingElse(); + assertGetTransactionAndCommitCount(4); + } + + public void testWithSingleMethodOverride() { + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.setTarget(new TestWithSingleMethodOverride()); + proxyFactory.addAdvice(this.ti); + + TestWithSingleMethodOverride proxy = (TestWithSingleMethodOverride) proxyFactory.getProxy(); + + proxy.doSomething(); + assertGetTransactionAndCommitCount(1); + + proxy.doSomethingElse(); + assertGetTransactionAndCommitCount(2); + + proxy.doSomethingCompletelyElse(); + assertGetTransactionAndCommitCount(3); + + proxy.doSomething(); + assertGetTransactionAndCommitCount(4); + } + + public void testWithSingleMethodOverrideInverted() { + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.setTarget(new TestWithSingleMethodOverrideInverted()); + proxyFactory.addAdvice(this.ti); + + TestWithSingleMethodOverrideInverted proxy = (TestWithSingleMethodOverrideInverted) proxyFactory.getProxy(); + + proxy.doSomething(); + assertGetTransactionAndCommitCount(1); + + proxy.doSomethingElse(); + assertGetTransactionAndCommitCount(2); + + proxy.doSomethingCompletelyElse(); + assertGetTransactionAndCommitCount(3); + + proxy.doSomething(); + assertGetTransactionAndCommitCount(4); + } + + public void testWithMultiMethodOverride() { + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.setTarget(new TestWithMultiMethodOverride()); + proxyFactory.addAdvice(this.ti); + + TestWithMultiMethodOverride proxy = (TestWithMultiMethodOverride) proxyFactory.getProxy(); + + proxy.doSomething(); + assertGetTransactionAndCommitCount(1); + + proxy.doSomethingElse(); + assertGetTransactionAndCommitCount(2); + + proxy.doSomethingCompletelyElse(); + assertGetTransactionAndCommitCount(3); + + proxy.doSomething(); + assertGetTransactionAndCommitCount(4); + } + + + public void testWithRollback() { + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.setTarget(new TestWithRollback()); + proxyFactory.addAdvice(this.ti); + + TestWithRollback proxy = (TestWithRollback) proxyFactory.getProxy(); + + try { + proxy.doSomethingErroneous(); + fail("Should throw IllegalStateException"); + } + catch (IllegalStateException ex) { + assertGetTransactionAndRollbackCount(1); + } + + try { + proxy.doSomethingElseErroneous(); + fail("Should throw IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + assertGetTransactionAndRollbackCount(2); + } + } + + public void testWithInterface() { + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.setTarget(new TestWithInterfaceImpl()); + proxyFactory.addInterface(TestWithInterface.class); + proxyFactory.addAdvice(this.ti); + + TestWithInterface proxy = (TestWithInterface) proxyFactory.getProxy(); + + proxy.doSomething(); + assertGetTransactionAndCommitCount(1); + + proxy.doSomethingElse(); + assertGetTransactionAndCommitCount(2); + + proxy.doSomethingElse(); + assertGetTransactionAndCommitCount(3); + + proxy.doSomething(); + assertGetTransactionAndCommitCount(4); + } + + public void testCrossClassInterfaceMethodLevelOnJdkProxy() throws Exception { + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.setTarget(new SomeServiceImpl()); + proxyFactory.addInterface(SomeService.class); + proxyFactory.addAdvice(this.ti); + + SomeService someService = (SomeService) proxyFactory.getProxy(); + + someService.bar(); + assertGetTransactionAndCommitCount(1); + + someService.foo(); + assertGetTransactionAndCommitCount(2); + + someService.fooBar(); + assertGetTransactionAndCommitCount(3); + } + + public void testCrossClassInterfaceOnJdkProxy() throws Exception { + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.setTarget(new OtherServiceImpl()); + proxyFactory.addInterface(OtherService.class); + proxyFactory.addAdvice(this.ti); + + OtherService otherService = (OtherService) proxyFactory.getProxy(); + + otherService.foo(); + assertGetTransactionAndCommitCount(1); + } + + private void assertGetTransactionAndCommitCount(int expectedCount) { + assertEquals(expectedCount, this.ptm.begun); + assertEquals(expectedCount, this.ptm.commits); + } + + private void assertGetTransactionAndRollbackCount(int expectedCount) { + assertEquals(expectedCount, this.ptm.begun); + assertEquals(expectedCount, this.ptm.rollbacks); + } + + + @Transactional + public static class TestClassLevelOnly { + + public void doSomething() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + + public void doSomethingElse() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + } + + + @Transactional + public static class TestWithSingleMethodOverride { + + public void doSomething() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + + @Transactional(readOnly = true) + public void doSomethingElse() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + + public void doSomethingCompletelyElse() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + } + + + @Transactional(readOnly = true) + public static class TestWithSingleMethodOverrideInverted { + + @Transactional + public void doSomething() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + + public void doSomethingElse() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + + public void doSomethingCompletelyElse() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + } + + + @Transactional + public static class TestWithMultiMethodOverride { + + @Transactional(readOnly = true) + public void doSomething() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + + @Transactional(readOnly = true) + public void doSomethingElse() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + + public void doSomethingCompletelyElse() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + } + + + @Transactional(rollbackFor = IllegalStateException.class) + public static class TestWithRollback { + + public void doSomethingErroneous() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + throw new IllegalStateException(); + } + + @Transactional(rollbackFor = IllegalArgumentException.class) + public void doSomethingElseErroneous() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + throw new IllegalArgumentException(); + } + } + + + @Transactional + public static interface TestWithInterface { + + public void doSomething(); + + @Transactional(readOnly = true) + public void doSomethingElse(); + } + + + public static class TestWithInterfaceImpl implements TestWithInterface { + + public void doSomething() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + + public void doSomethingElse() { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + } + + + public static interface SomeService { + + void foo(); + + @Transactional + void bar(); + + @Transactional(readOnly = true) + void fooBar(); + } + + + public static class SomeServiceImpl implements SomeService { + + public void bar() { + } + + @Transactional + public void foo() { + } + + @Transactional(readOnly = false) + public void fooBar() { + } + } + + + public static interface OtherService { + + void foo(); + } + + + @Transactional + public static class OtherServiceImpl implements OtherService { + + public void foo() { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionNamespaceHandlerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionNamespaceHandlerTests.java new file mode 100644 index 00000000000..fb813b49e47 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionNamespaceHandlerTests.java @@ -0,0 +1,135 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.annotation; + +import java.lang.management.ManagementFactory; +import java.util.Collection; +import java.util.Map; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import junit.framework.TestCase; + +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.generic.GenericBeanFactoryAccessor; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.jmx.export.annotation.ManagedOperation; +import org.springframework.jmx.export.annotation.ManagedResource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.CallCountingTransactionManager; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class AnnotationTransactionNamespaceHandlerTests extends TestCase { + + private ConfigurableApplicationContext context; + + public void setUp() { + this.context = new ClassPathXmlApplicationContext( + "org/springframework/transaction/annotation/annotationTransactionNamespaceHandlerTests.xml"); + } + + protected void tearDown() { + this.context.close(); + } + + public void testIsProxy() throws Exception { + TransactionalTestBean bean = getTestBean(); + assertTrue("testBean is not a proxy", AopUtils.isAopProxy(bean)); + Map services = new GenericBeanFactoryAccessor(this.context).getBeansWithAnnotation(Service.class); + assertTrue("Stereotype annotation not visible", services.containsKey("testBean")); + } + + public void testInvokeTransactional() throws Exception { + TransactionalTestBean testBean = getTestBean(); + CallCountingTransactionManager ptm = (CallCountingTransactionManager) context.getBean("transactionManager"); + + // try with transactional + assertEquals("Should not have any started transactions", 0, ptm.begun); + testBean.findAllFoos(); + assertEquals("Should have 1 started transaction", 1, ptm.begun); + assertEquals("Should have 1 committed transaction", 1, ptm.commits); + + // try with non-transaction + testBean.doSomething(); + assertEquals("Should not have started another transaction", 1, ptm.begun); + + // try with exceptional + try { + testBean.exceptional(new IllegalArgumentException("foo")); + fail("Should NEVER get here"); + } + catch (Throwable throwable) { + assertEquals("Should have another started transaction", 2, ptm.begun); + assertEquals("Should have 1 rolled back transaction", 1, ptm.rollbacks); + + } + } + + public void testNonPublicMethodsNotAdvised() { + TransactionalTestBean testBean = getTestBean(); + CallCountingTransactionManager ptm = (CallCountingTransactionManager) context.getBean("transactionManager"); + + assertEquals("Should not have any started transactions", 0, ptm.begun); + testBean.annotationsOnProtectedAreIgnored(); + assertEquals("Should not have any started transactions", 0, ptm.begun); + } + + public void testMBeanExportAlsoWorks() throws Exception { + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + assertEquals("done", + server.invoke(ObjectName.getInstance("test:type=TestBean"), "doSomething", new Object[0], new String[0])); + } + + private TransactionalTestBean getTestBean() { + return (TransactionalTestBean) context.getBean("testBean"); + } + + + @Service + @ManagedResource("test:type=TestBean") + public static class TransactionalTestBean { + + @Transactional(readOnly = true) + public Collection findAllFoos() { + return null; + } + + @Transactional + public void saveFoo() { + } + + @Transactional + public void exceptional(Throwable t) throws Throwable { + throw t; + } + + @ManagedOperation + public String doSomething() { + return "done"; + } + + @Transactional + protected void annotationsOnProtectedAreIgnored() { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/annotationTransactionNamespaceHandlerTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/annotationTransactionNamespaceHandlerTests.xml new file mode 100644 index 00000000000..d30fd87be1a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/annotation/annotationTransactionNamespaceHandlerTests.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/config/AnnotationDrivenTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/config/AnnotationDrivenTests.java new file mode 100644 index 00000000000..072393d935a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/config/AnnotationDrivenTests.java @@ -0,0 +1,49 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.config; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.aop.support.AopUtils; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class AnnotationDrivenTests extends TestCase { + + public void testWithProxyTargetClass() throws Exception { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("annotationDrivenProxyTargetClassTests.xml", getClass()); + TransactionalService service = (TransactionalService) context.getBean("service"); + assertTrue(AopUtils.isCglibProxy(service)); + service.setBeanName("someName"); + } + + + public static class TransactionCheckingInterceptor implements MethodInterceptor { + + public Object invoke(MethodInvocation methodInvocation) throws Throwable { + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + return methodInvocation.proceed(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/config/TransactionalService.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/config/TransactionalService.java new file mode 100644 index 00000000000..74aee4b1149 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/config/TransactionalService.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.config; + +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author Rob Harrop + */ +@Transactional +public class TransactionalService implements BeanNameAware { + + public void setBeanName(String name) { + // just for testing :) + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/config/annotationDrivenProxyTargetClassTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/transaction/config/annotationDrivenProxyTargetClassTests.xml new file mode 100644 index 00000000000..8f7ddc23b2c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/config/annotationDrivenProxyTargetClassTests.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/TypeUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/TypeUtilsTests.java new file mode 100644 index 00000000000..a33d49fc2f6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/TypeUtilsTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; + +import junit.framework.TestCase; + +/** + * @author Juergen Hoeller + */ +public class TypeUtilsTests extends TestCase { + + public static List objects; + + public static List openObjects; + + public static List strings; + + public void testClasses() { + assertTrue(TypeUtils.isAssignable(Object.class, Object.class)); + assertTrue(TypeUtils.isAssignable(Object.class, String.class)); + assertFalse(TypeUtils.isAssignable(String.class, Object.class)); + assertTrue(TypeUtils.isAssignable(List.class, List.class)); + assertTrue(TypeUtils.isAssignable(List.class, LinkedList.class)); + assertFalse(TypeUtils.isAssignable(List.class, Collection.class)); + assertFalse(TypeUtils.isAssignable(List.class, HashSet.class)); + } + + public void testParameterizedTypes() throws Exception { + Type objectsType = getClass().getField("objects").getGenericType(); + Type openObjectsType = getClass().getField("openObjects").getGenericType(); + Type stringsType = getClass().getField("strings").getGenericType(); + assertTrue(TypeUtils.isAssignable(objectsType, objectsType)); + assertTrue(TypeUtils.isAssignable(openObjectsType, openObjectsType)); + assertTrue(TypeUtils.isAssignable(stringsType, stringsType)); + assertTrue(TypeUtils.isAssignable(openObjectsType, objectsType)); + assertTrue(TypeUtils.isAssignable(openObjectsType, stringsType)); + assertFalse(TypeUtils.isAssignable(stringsType, objectsType)); + assertFalse(TypeUtils.isAssignable(objectsType, stringsType)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/annotation/PortletAnnotationControllerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/annotation/PortletAnnotationControllerTests.java new file mode 100644 index 00000000000..714f250dcf9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/annotation/PortletAnnotationControllerTests.java @@ -0,0 +1,777 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.mvc.annotation; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.portlet.ActionRequest; +import javax.portlet.ActionResponse; +import javax.portlet.PortletContext; +import javax.portlet.PortletMode; +import javax.portlet.PortletRequest; +import javax.portlet.PortletSession; +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; +import javax.portlet.UnavailableException; + +import junit.framework.TestCase; + +import org.springframework.beans.BeansException; +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigUtils; +import org.springframework.core.MethodParameter; +import org.springframework.mock.web.portlet.MockActionRequest; +import org.springframework.mock.web.portlet.MockActionResponse; +import org.springframework.mock.web.portlet.MockPortletConfig; +import org.springframework.mock.web.portlet.MockPortletContext; +import org.springframework.mock.web.portlet.MockRenderRequest; +import org.springframework.mock.web.portlet.MockRenderResponse; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ExtendedModelMap; +import org.springframework.ui.Model; +import org.springframework.ui.ModelMap; +import org.springframework.validation.BindingResult; +import org.springframework.validation.Errors; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.support.WebArgumentResolver; +import org.springframework.web.bind.support.WebBindingInitializer; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.context.support.GenericWebApplicationContext; +import org.springframework.web.portlet.DispatcherPortlet; +import org.springframework.web.portlet.ModelAndView; +import org.springframework.web.portlet.context.StaticPortletApplicationContext; +import org.springframework.web.portlet.mvc.AbstractController; + +/** + * @author Juergen Hoeller + * @since 2.5 + */ +public class PortletAnnotationControllerTests extends TestCase { + + public void testStandardHandleMethod() throws Exception { + DispatcherPortlet portlet = new DispatcherPortlet() { + protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyController.class)); + wac.refresh(); + return wac; + } + }; + portlet.init(new MockPortletConfig()); + + MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW); + MockRenderResponse response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("test", response.getContentAsString()); + } + + public void testAdaptedHandleMethods() throws Exception { + doTestAdaptedHandleMethods(MyAdaptedController.class); + } + + public void testAdaptedHandleMethods2() throws Exception { + doTestAdaptedHandleMethods(MyAdaptedController2.class); + } + + public void testAdaptedHandleMethods3() throws Exception { + doTestAdaptedHandleMethods(MyAdaptedController3.class); + } + + public void doTestAdaptedHandleMethods(final Class controllerClass) throws Exception { + DispatcherPortlet portlet = new DispatcherPortlet() { + protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(controllerClass)); + wac.refresh(); + return wac; + } + }; + portlet.init(new MockPortletConfig()); + + MockActionRequest actionRequest = new MockActionRequest(PortletMode.VIEW); + MockActionResponse actionResponse = new MockActionResponse(); + portlet.processAction(actionRequest, actionResponse); + assertEquals("value", actionResponse.getRenderParameter("test")); + + MockRenderRequest request = new MockRenderRequest(PortletMode.EDIT); + request.addParameter("param1", "value1"); + request.addParameter("param2", "2"); + MockRenderResponse response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("test-value1-2", response.getContentAsString()); + + request = new MockRenderRequest(PortletMode.HELP); + request.addParameter("name", "name1"); + request.addParameter("age", "2"); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("test-name1-2", response.getContentAsString()); + + request = new MockRenderRequest(PortletMode.VIEW); + request.addParameter("name", "name1"); + request.addParameter("age", "value2"); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("test-name1-typeMismatch", response.getContentAsString()); + } + + public void testFormController() throws Exception { + DispatcherPortlet portlet = new DispatcherPortlet() { + protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyFormController.class)); + wac.refresh(); + return wac; + } + + protected void render(ModelAndView mv, RenderRequest request, RenderResponse response) throws Exception { + new TestView().render(mv.getViewName(), mv.getModel(), request, response); + } + }; + portlet.init(new MockPortletConfig()); + + MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW); + request.addParameter("name", "name1"); + request.addParameter("age", "value2"); + MockRenderResponse response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString()); + } + + public void testModelFormController() throws Exception { + DispatcherPortlet portlet = new DispatcherPortlet() { + protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyModelFormController.class)); + wac.refresh(); + return wac; + } + + protected void render(ModelAndView mv, RenderRequest request, RenderResponse response) throws Exception { + new TestView().render(mv.getViewName(), mv.getModel(), request, response); + } + }; + portlet.init(new MockPortletConfig()); + + MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW); + request.addParameter("name", "name1"); + request.addParameter("age", "value2"); + MockRenderResponse response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString()); + } + + public void testCommandProvidingFormController() throws Exception { + DispatcherPortlet portlet = new DispatcherPortlet() { + protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyCommandProvidingFormController.class)); + RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class); + adapterDef.getPropertyValues().addPropertyValue("webBindingInitializer", new MyWebBindingInitializer()); + wac.registerBeanDefinition("handlerAdapter", adapterDef); + wac.refresh(); + return wac; + } + + protected void render(ModelAndView mv, RenderRequest request, RenderResponse response) throws Exception { + new TestView().render(mv.getViewName(), mv.getModel(), request, response); + } + }; + portlet.init(new MockPortletConfig()); + + MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW); + request.addParameter("defaultName", "myDefaultName"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + MockRenderResponse response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + } + + public void testTypedCommandProvidingFormController() throws Exception { + DispatcherPortlet portlet = new DispatcherPortlet() { + protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyTypedCommandProvidingFormController.class)); + wac.registerBeanDefinition("controller2", new RootBeanDefinition(MyOtherTypedCommandProvidingFormController.class)); + RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class); + adapterDef.getPropertyValues().addPropertyValue("webBindingInitializer", new MyWebBindingInitializer()); + adapterDef.getPropertyValues().addPropertyValue("customArgumentResolver", new MySpecialArgumentResolver()); + wac.registerBeanDefinition("handlerAdapter", adapterDef); + wac.refresh(); + return wac; + } + protected void render(ModelAndView mv, RenderRequest request, RenderResponse response) throws Exception { + new TestView().render(mv.getViewName(), mv.getModel(), request, response); + } + }; + portlet.init(new MockPortletConfig()); + + MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW); + request.addParameter("myParam", "myValue"); + request.addParameter("defaultName", "10"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + MockRenderResponse response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myView-Integer:10-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + + request = new MockRenderRequest(PortletMode.VIEW); + request.addParameter("myParam", "myOtherValue"); + request.addParameter("defaultName", "10"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myOtherView-Integer:10-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + + request = new MockRenderRequest(PortletMode.EDIT); + request.addParameter("myParam", "myValue"); + request.addParameter("defaultName", "10"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myView-myName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + } + + public void testBinderInitializingCommandProvidingFormController() throws Exception { + DispatcherPortlet portlet = new DispatcherPortlet() { + protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyBinderInitializingCommandProvidingFormController.class)); + wac.refresh(); + return wac; + } + + protected void render(ModelAndView mv, RenderRequest request, RenderResponse response) throws Exception { + new TestView().render(mv.getViewName(), mv.getModel(), request, response); + } + }; + portlet.init(new MockPortletConfig()); + + MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW); + request.addParameter("defaultName", "myDefaultName"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + MockRenderResponse response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + } + + public void testSpecificBinderInitializingCommandProvidingFormController() throws Exception { + DispatcherPortlet portlet = new DispatcherPortlet() { + protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException { + StaticPortletApplicationContext wac = new StaticPortletApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MySpecificBinderInitializingCommandProvidingFormController.class)); + wac.refresh(); + return wac; + } + + protected void render(ModelAndView mv, RenderRequest request, RenderResponse response) throws Exception { + new TestView().render(mv.getViewName(), mv.getModel(), request, response); + } + }; + portlet.init(new MockPortletConfig()); + + MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW); + request.addParameter("defaultName", "myDefaultName"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + MockRenderResponse response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + } + + public void testParameterDispatchingController() throws Exception { + DispatcherPortlet portlet = new DispatcherPortlet() { + protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException { + StaticPortletApplicationContext wac = new StaticPortletApplicationContext(); + wac.setPortletContext(new MockPortletContext()); + RootBeanDefinition bd = new RootBeanDefinition(MyParameterDispatchingController.class); + bd.setScope(WebApplicationContext.SCOPE_REQUEST); + wac.registerBeanDefinition("controller", bd); + AnnotationConfigUtils.registerAnnotationConfigProcessors(wac); + wac.refresh(); + return wac; + } + }; + portlet.init(new MockPortletConfig()); + + MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW); + MockRenderResponse response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myView", response.getContentAsString()); + + request = new MockRenderRequest(PortletMode.VIEW); + request.addParameter("view", "other"); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myOtherView", response.getContentAsString()); + + request = new MockRenderRequest(PortletMode.VIEW); + request.addParameter("view", "my"); + request.addParameter("lang", "de"); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myLangView", response.getContentAsString()); + + request = new MockRenderRequest(PortletMode.VIEW); + request.addParameter("surprise", "!"); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("mySurpriseView", response.getContentAsString()); + } + + public void testTypeLevelParameterDispatchingController() throws Exception { + DispatcherPortlet portlet = new DispatcherPortlet() { + protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException { + StaticPortletApplicationContext wac = new StaticPortletApplicationContext(); + wac.setPortletContext(new MockPortletContext()); + RootBeanDefinition bd = new RootBeanDefinition(MyTypeLevelParameterDispatchingController.class); + bd.setScope(WebApplicationContext.SCOPE_REQUEST); + wac.registerBeanDefinition("controller", bd); + RootBeanDefinition bd2 = new RootBeanDefinition(MySpecialParameterDispatchingController.class); + bd2.setScope(WebApplicationContext.SCOPE_REQUEST); + wac.registerBeanDefinition("controller2", bd2); + RootBeanDefinition bd3 = new RootBeanDefinition(MyOtherSpecialParameterDispatchingController.class); + bd3.setScope(WebApplicationContext.SCOPE_REQUEST); + wac.registerBeanDefinition("controller3", bd3); + RootBeanDefinition bd4 = new RootBeanDefinition(MyParameterDispatchingController.class); + bd4.setScope(WebApplicationContext.SCOPE_REQUEST); + wac.registerBeanDefinition("controller4", bd4); + AnnotationConfigUtils.registerAnnotationConfigProcessors(wac); + wac.refresh(); + return wac; + } + }; + portlet.init(new MockPortletConfig()); + + MockRenderRequest request = new MockRenderRequest(PortletMode.HELP); + MockRenderResponse response = new MockRenderResponse(); + try { + portlet.render(request, response); + fail("Should have thrown UnavailableException"); + } + catch (UnavailableException ex) { + // expected + } + + request = new MockRenderRequest(PortletMode.EDIT); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myDefaultView", response.getContentAsString()); + + request = new MockRenderRequest(PortletMode.EDIT); + request.addParameter("myParam", "myValue"); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myView", response.getContentAsString()); + + request = new MockRenderRequest(PortletMode.EDIT); + request.addParameter("myParam", "mySpecialValue"); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("mySpecialView", response.getContentAsString()); + + request = new MockRenderRequest(PortletMode.EDIT); + request.addParameter("myParam", "myOtherSpecialValue"); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myOtherSpecialView", response.getContentAsString()); + + request = new MockRenderRequest(PortletMode.VIEW); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myView", response.getContentAsString()); + + request = new MockRenderRequest(PortletMode.EDIT); + request.addParameter("myParam", "myValue"); + request.addParameter("view", "other"); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myOtherView", response.getContentAsString()); + + request = new MockRenderRequest(PortletMode.EDIT); + request.addParameter("myParam", "myValue"); + request.addParameter("view", "my"); + request.addParameter("lang", "de"); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("myLangView", response.getContentAsString()); + + request = new MockRenderRequest(PortletMode.EDIT); + request.addParameter("myParam", "myValue"); + request.addParameter("surprise", "!"); + response = new MockRenderResponse(); + portlet.render(request, response); + assertEquals("mySurpriseView", response.getContentAsString()); + } + + + @RequestMapping("VIEW") + private static class MyController extends AbstractController { + + protected ModelAndView handleRenderRequestInternal(RenderRequest request, RenderResponse response) throws Exception { + response.getWriter().write("test"); + return null; + } + } + + + @Controller + private static class MyAdaptedController { + + @RequestMapping("VIEW") + public void myHandle(ActionRequest request, ActionResponse response) throws IOException { + response.setRenderParameter("test", "value"); + } + + @RequestMapping("EDIT") + public void myHandle(@RequestParam("param1")String p1, @RequestParam("param2")int p2, RenderResponse response) throws IOException { + response.getWriter().write("test-" + p1 + "-" + p2); + } + + @RequestMapping("HELP") + public void myHandle(TestBean tb, RenderResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge()); + } + + @RequestMapping("VIEW") + public void myHandle(TestBean tb, Errors errors, RenderResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode()); + } + } + + + @Controller + private static class MyAdaptedController2 { + + @RequestMapping("VIEW") + public void myHandle(ActionRequest request, ActionResponse response) throws IOException { + response.setRenderParameter("test", "value"); + } + + @RequestMapping("EDIT") + public void myHandle(@RequestParam("param1")String p1, int param2, RenderResponse response) throws IOException { + response.getWriter().write("test-" + p1 + "-" + param2); + } + + @RequestMapping("HELP") + public void myHandle(TestBean tb, RenderResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge()); + } + + @RequestMapping("VIEW") + public void myHandle(TestBean tb, Errors errors, RenderResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode()); + } + } + + + @Controller + @RequestMapping({"VIEW", "EDIT", "HELP"}) + private static class MyAdaptedController3 { + + @RequestMapping + public void myHandle(ActionRequest request, ActionResponse response) { + response.setRenderParameter("test", "value"); + } + + @RequestMapping("EDIT") + public void myHandle(@RequestParam("param1")String p1, @RequestParam("param2")int p2, RenderResponse response) throws IOException { + response.getWriter().write("test-" + p1 + "-" + p2); + } + + @RequestMapping("HELP") + public void myHandle(TestBean tb, RenderResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge()); + } + + @RequestMapping + public void myHandle(TestBean tb, Errors errors, RenderResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode()); + } + } + + + @Controller + private static class MyFormController { + + @ModelAttribute("testBeanList") + public List getTestBeans() { + List list = new LinkedList(); + list.add(new TestBean("tb1")); + list.add(new TestBean("tb2")); + return list; + } + + @RequestMapping("VIEW") + public String myHandle(@ModelAttribute("myCommand")TestBean tb, BindingResult errors, ModelMap model) { + if (!model.containsKey("myKey")) { + model.addAttribute("myKey", "myValue"); + } + return "myView"; + } + } + + + @Controller + private static class MyModelFormController { + + @ModelAttribute + public List getTestBeans() { + List list = new LinkedList(); + list.add(new TestBean("tb1")); + list.add(new TestBean("tb2")); + return list; + } + + @RequestMapping("VIEW") + public String myHandle(@ModelAttribute("myCommand")TestBean tb, BindingResult errors, Model model) { + if (!model.containsAttribute("myKey")) { + model.addAttribute("myKey", "myValue"); + } + return "myView"; + } + } + + + @Controller + private static class MyCommandProvidingFormController extends MyFormController { + + @ModelAttribute("myCommand") + private TestBean createTestBean( + @RequestParam T defaultName, Map model, @RequestParam Date date) { + model.put("myKey", "myOriginalValue"); + return new TestBean(defaultName.getClass().getSimpleName() + ":" + defaultName.toString()); + } + + @RequestMapping("VIEW") + public String myHandle(@ModelAttribute("myCommand") TestBean tb, BindingResult errors, ModelMap model) { + if (!model.containsKey("myKey")) { + model.addAttribute("myKey", "myValue"); + } + return "myView"; + } + + @RequestMapping("EDIT") + public String myOtherHandle(TB tb, BindingResult errors, ExtendedModelMap model, MySpecialArg arg) { + TestBean tbReal = (TestBean) tb; + tbReal.setName("myName"); + assertTrue(model.get("ITestBean") instanceof DerivedTestBean); + assertNotNull(arg); + return super.myHandle(tbReal, errors, model); + } + + @ModelAttribute + protected TB2 getModelAttr() { + return (TB2) new DerivedTestBean(); + } + } + + + private static class MySpecialArg { + + public MySpecialArg(String value) { + } + } + + + @Controller + @RequestMapping(params = "myParam=myValue") + private static class MyTypedCommandProvidingFormController + extends MyCommandProvidingFormController { + + } + + + @Controller + @RequestMapping(params = "myParam=myOtherValue") + private static class MyOtherTypedCommandProvidingFormController + extends MyCommandProvidingFormController { + + @RequestMapping("VIEW") + public String myHandle(@ModelAttribute("myCommand") TestBean tb, BindingResult errors, ModelMap model) { + if (!model.containsKey("myKey")) { + model.addAttribute("myKey", "myValue"); + } + return "myOtherView"; + } + } + + + @Controller + private static class MyBinderInitializingCommandProvidingFormController extends MyCommandProvidingFormController { + + @InitBinder + private void initBinder(WebDataBinder binder) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + dateFormat.setLenient(false); + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); + } + } + + + @Controller + private static class MySpecificBinderInitializingCommandProvidingFormController extends MyCommandProvidingFormController { + + @SuppressWarnings("unused") + @InitBinder({"myCommand", "date"}) + private void initBinder(WebDataBinder binder) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + dateFormat.setLenient(false); + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); + } + } + + + private static class MyWebBindingInitializer implements WebBindingInitializer { + + public void initBinder(WebDataBinder binder, WebRequest request) { + assertNotNull(request.getLocale()); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + dateFormat.setLenient(false); + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); + } + } + + + private static class MySpecialArgumentResolver implements WebArgumentResolver { + + public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) { + if (methodParameter.getParameterType().equals(MySpecialArg.class)) { + return new MySpecialArg("myValue"); + } + return UNRESOLVED; + } + } + + + @Controller + @RequestMapping("VIEW") + private static class MyParameterDispatchingController { + + @Autowired + private PortletContext portletContext; + + @Autowired + private PortletSession session; + + @Autowired + private PortletRequest request; + + @RequestMapping + public void myHandle(RenderResponse response) throws IOException { + if (this.portletContext == null || this.session == null || this.request == null) { + throw new IllegalStateException(); + } + response.getWriter().write("myView"); + } + + @RequestMapping(params = {"view", "!lang"}) + public void myOtherHandle(RenderResponse response) throws IOException { + response.getWriter().write("myOtherView"); + } + + @RequestMapping(params = {"view=my", "lang=de"}) + public void myLangHandle(RenderResponse response) throws IOException { + response.getWriter().write("myLangView"); + } + + @RequestMapping(params = "surprise") + public void mySurpriseHandle(RenderResponse response) throws IOException { + response.getWriter().write("mySurpriseView"); + } + } + + + @Controller + @RequestMapping(value = "EDIT", params = "myParam=myValue") + private static class MyTypeLevelParameterDispatchingController extends MyParameterDispatchingController { + + } + + + @Controller + @RequestMapping("EDIT") + private static class MySpecialParameterDispatchingController { + + @RequestMapping(params = "myParam=mySpecialValue") + public void myHandle(RenderResponse response) throws IOException { + response.getWriter().write("mySpecialView"); + } + + @RequestMapping + public void myDefaultHandle(RenderResponse response) throws IOException { + response.getWriter().write("myDefaultView"); + } + } + + + @Controller + @RequestMapping("EDIT") + private static class MyOtherSpecialParameterDispatchingController { + + @RequestMapping(params = "myParam=myOtherSpecialValue") + public void myHandle(RenderResponse response) throws IOException { + response.getWriter().write("myOtherSpecialView"); + } + } + + + private static class TestView { + + public void render(String viewName, Map model, RenderRequest request, RenderResponse response) throws Exception { + TestBean tb = (TestBean) model.get("testBean"); + if (tb == null) { + tb = (TestBean) model.get("myCommand"); + } + if (tb.getName().endsWith("myDefaultName")) { + assertTrue(tb.getDate().getYear() == 107); + } + Errors errors = (Errors) model.get(BindingResult.MODEL_KEY_PREFIX + "testBean"); + if (errors == null) { + errors = (Errors) model.get(BindingResult.MODEL_KEY_PREFIX + "myCommand"); + } + if (errors.hasFieldErrors("date")) { + throw new IllegalStateException(); + } + List testBeans = (List) model.get("testBeanList"); + response.getWriter().write(viewName + "-" + tb.getName() + "-" + errors.getFieldError("age").getCode() + + "-" + testBeans.get(0).getName() + "-" + model.get("myKey")); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/AdminController.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/AdminController.java new file mode 100644 index 00000000000..9050e214401 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/AdminController.java @@ -0,0 +1,27 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.annotation; + +import org.springframework.stereotype.Controller; + +/** + * @author Juergen Hoeller + */ +@Controller +public class AdminController { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/BuyForm.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/BuyForm.java new file mode 100644 index 00000000000..2ec6c6dd0dc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/BuyForm.java @@ -0,0 +1,27 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.annotation; + +import org.springframework.stereotype.Controller; + +/** + * @author Juergen Hoeller + */ +@Controller +public class BuyForm { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/ControllerClassNameHandlerMappingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/ControllerClassNameHandlerMappingTests.java new file mode 100644 index 00000000000..ec3bd838dd3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/ControllerClassNameHandlerMappingTests.java @@ -0,0 +1,117 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.annotation; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.XmlWebApplicationContext; +import org.springframework.web.servlet.HandlerExecutionChain; +import org.springframework.web.servlet.HandlerMapping; + +/** + * @author Juergen Hoeller + */ +public class ControllerClassNameHandlerMappingTests extends TestCase { + + public static final String LOCATION = "/org/springframework/web/servlet/mvc/annotation/class-mapping.xml"; + + private XmlWebApplicationContext wac; + + private HandlerMapping hm; + + private HandlerMapping hm2; + + private HandlerMapping hm3; + + private HandlerMapping hm4; + + public void setUp() throws Exception { + MockServletContext sc = new MockServletContext(""); + this.wac = new XmlWebApplicationContext(); + this.wac.setServletContext(sc); + this.wac.setConfigLocations(new String[] {LOCATION}); + this.wac.refresh(); + this.hm = (HandlerMapping) this.wac.getBean("mapping"); + this.hm2 = (HandlerMapping) this.wac.getBean("mapping2"); + this.hm3 = (HandlerMapping) this.wac.getBean("mapping3"); + this.hm4 = (HandlerMapping) this.wac.getBean("mapping4"); + } + + public void testIndexUri() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("index"), chain.getHandler()); + + request = new MockHttpServletRequest("GET", "/index/product"); + chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("index"), chain.getHandler()); + } + + public void testMapSimpleUri() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + + request = new MockHttpServletRequest("GET", "/welcome/product"); + chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithContextPath() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/welcome"); + request.setContextPath("/myapp"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithoutControllerSuffix() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/buyform"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("buy"), chain.getHandler()); + + request = new MockHttpServletRequest("GET", "/buyform/product"); + chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("buy"), chain.getHandler()); + } + + public void testWithBasePackage() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/mvc/annotation/welcome"); + HandlerExecutionChain chain = this.hm2.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithBasePackageAndCaseSensitive() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/mvc/annotation/buyForm"); + HandlerExecutionChain chain = this.hm2.getHandler(request); + assertEquals(this.wac.getBean("buy"), chain.getHandler()); + } + + public void testWithFullBasePackage() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/welcome"); + HandlerExecutionChain chain = this.hm3.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithRootAsBasePackage() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/org/springframework/web/servlet/mvc/annotation/welcome"); + HandlerExecutionChain chain = this.hm4.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/IndexController.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/IndexController.java new file mode 100644 index 00000000000..ebbfbdc33fe --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/IndexController.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.annotation; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Juergen Hoeller + */ +@Controller +public class IndexController { + + @RequestMapping + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { + return new ModelAndView("indexView"); + } + +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/MethodNameDispatchingController.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/MethodNameDispatchingController.java new file mode 100644 index 00000000000..709d7422d5c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/MethodNameDispatchingController.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.annotation; + +import java.io.IOException; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * @author Juergen Hoeller + */ +@Controller +@RequestMapping("/*.do") +public class MethodNameDispatchingController { + + @RequestMapping + public void myHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myView"); + } + + @RequestMapping + public void myOtherHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myOtherView"); + } + + @RequestMapping(method = RequestMethod.POST) + public void myLangHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myLangView"); + } + + @RequestMapping(method = RequestMethod.POST) + public void mySurpriseHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("mySurpriseView"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java new file mode 100644 index 00000000000..78fb102d3ac --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java @@ -0,0 +1,1137 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.annotation; + +import java.io.IOException; +import java.io.Writer; +import java.security.Principal; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; +import org.springframework.aop.interceptor.SimpleTraceInterceptor; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.context.annotation.AnnotationConfigUtils; +import org.springframework.core.MethodParameter; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletConfig; +import org.springframework.mock.web.MockServletContext; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ExtendedModelMap; +import org.springframework.ui.Model; +import org.springframework.ui.ModelMap; +import org.springframework.validation.BindingResult; +import org.springframework.validation.Errors; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.support.WebArgumentResolver; +import org.springframework.web.bind.support.WebBindingInitializer; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.context.support.GenericWebApplicationContext; +import org.springframework.web.servlet.DispatcherServlet; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.View; +import org.springframework.web.servlet.ViewResolver; +import org.springframework.web.servlet.mvc.AbstractController; +import org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver; +import org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping; +import org.springframework.web.servlet.view.InternalResourceViewResolver; +import org.springframework.web.util.NestedServletException; + +/** + * @author Juergen Hoeller + * @author Sam Brannen + * @since 2.5 + */ +public class ServletAnnotationControllerTests extends TestCase { + + public void testStandardHandleMethod() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyController.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("test", response.getContentAsString()); + } + + public void testProxiedStandardHandleMethod() throws Exception { + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyController.class)); + DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator(); + autoProxyCreator.setBeanFactory(wac.getBeanFactory()); + wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator); + wac.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor())); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("test", response.getContentAsString()); + } + + public void testEmptyParameterListHandleMethod() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(EmptyParameterListHandlerMethodController.class)); + RootBeanDefinition vrDef = new RootBeanDefinition(InternalResourceViewResolver.class); + vrDef.getPropertyValues().addPropertyValue("suffix", ".jsp"); + wac.registerBeanDefinition("viewResolver", vrDef); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/emptyParameterListHandler"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + EmptyParameterListHandlerMethodController.called = false; + servlet.service(request, response); + assertTrue(EmptyParameterListHandlerMethodController.called); + assertEquals("", response.getContentAsString()); + } + + public void testAdaptedHandleMethods() throws Exception { + doTestAdaptedHandleMethods(MyAdaptedController.class); + } + + public void testAdaptedHandleMethods2() throws Exception { + doTestAdaptedHandleMethods(MyAdaptedController2.class); + } + + public void testAdaptedHandleMethods3() throws Exception { + doTestAdaptedHandleMethods(MyAdaptedController3.class); + } + + private void doTestAdaptedHandleMethods(final Class controllerClass) throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(controllerClass)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath1.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + request.addParameter("param1", "value1"); + request.addParameter("param2", "2"); + servlet.service(request, response); + assertEquals("test", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myPath2.do"); + request.addParameter("param1", "value1"); + request.addParameter("param2", "2"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("test-value1-2", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myPath3.do"); + request.addParameter("param1", "value1"); + request.addParameter("param2", "2"); + request.addParameter("name", "name1"); + request.addParameter("age", "2"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("test-name1-2", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myPath4.do"); + request.addParameter("param1", "value1"); + request.addParameter("param2", "2"); + request.addParameter("name", "name1"); + request.addParameter("age", "value2"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("test-name1-typeMismatch", response.getContentAsString()); + } + + public void testFormController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyFormController.class)); + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + request.addParameter("name", "name1"); + request.addParameter("age", "value2"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString()); + } + + public void testModelFormController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyModelFormController.class)); + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + request.addParameter("name", "name1"); + request.addParameter("age", "value2"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString()); + } + + public void testProxiedFormController() throws Exception { + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyFormController.class)); + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); + DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator(); + autoProxyCreator.setBeanFactory(wac.getBeanFactory()); + wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator); + wac.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor())); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + request.addParameter("name", "name1"); + request.addParameter("age", "value2"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString()); + } + + public void testCommandProvidingFormController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyCommandProvidingFormController.class)); + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); + RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class); + adapterDef.getPropertyValues().addPropertyValue("webBindingInitializer", new MyWebBindingInitializer()); + wac.registerBeanDefinition("handlerAdapter", adapterDef); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + request.addParameter("defaultName", "myDefaultName"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + } + + public void testTypedCommandProvidingFormController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyTypedCommandProvidingFormController.class)); + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); + RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class); + adapterDef.getPropertyValues().addPropertyValue("webBindingInitializer", new MyWebBindingInitializer()); + adapterDef.getPropertyValues().addPropertyValue("customArgumentResolver", new MySpecialArgumentResolver()); + wac.registerBeanDefinition("handlerAdapter", adapterDef); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + request.addParameter("defaultName", "10"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-Integer:10-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myOtherPath.do"); + request.addParameter("defaultName", "10"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-myName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myThirdPath.do"); + request.addParameter("defaultName", "10"); + request.addParameter("age", "100"); + request.addParameter("date", "2007-10-02"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-special-99-special-99", response.getContentAsString()); + } + + public void testBinderInitializingCommandProvidingFormController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyBinderInitializingCommandProvidingFormController.class)); + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + request.addParameter("defaultName", "myDefaultName"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + } + + public void testSpecificBinderInitializingCommandProvidingFormController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MySpecificBinderInitializingCommandProvidingFormController.class)); + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + request.addParameter("defaultName", "myDefaultName"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + } + + public void testParameterDispatchingController() throws Exception { + final MockServletContext servletContext = new MockServletContext(); + final MockServletConfig servletConfig = new MockServletConfig(servletContext); + + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.setServletContext(servletContext); + RootBeanDefinition bd = new RootBeanDefinition(MyParameterDispatchingController.class); + bd.setScope(WebApplicationContext.SCOPE_REQUEST); + wac.registerBeanDefinition("controller", bd); + AnnotationConfigUtils.registerAnnotationConfigProcessors(wac); + wac.getBeanFactory().registerResolvableDependency(ServletConfig.class, servletConfig); + wac.refresh(); + return wac; + } + }; + servlet.init(servletConfig); + + MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + HttpSession session = request.getSession(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + assertSame(servletContext, request.getAttribute("servletContext")); + assertSame(servletConfig, request.getAttribute("servletConfig")); + assertSame(session, request.getAttribute("session")); + assertSame(request, request.getAttribute("request")); + + request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); + response = new MockHttpServletResponse(); + session = request.getSession(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + assertSame(servletContext, request.getAttribute("servletContext")); + assertSame(servletConfig, request.getAttribute("servletConfig")); + assertSame(session, request.getAttribute("session")); + assertSame(request, request.getAttribute("request")); + + request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); + request.addParameter("view", "other"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myOtherView", response.getContentAsString()); + + request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); + request.addParameter("view", "my"); + request.addParameter("lang", "de"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myLangView", response.getContentAsString()); + + request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); + request.addParameter("surprise", "!"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("mySurpriseView", response.getContentAsString()); + } + + public void testMethodNameDispatchingController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MethodNameDispatchingController.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myHandle.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myOtherHandle.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myOtherView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/myLangHandle.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myLangView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/mySurpriseHandle.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("mySurpriseView", response.getContentAsString()); + } + + public void testMethodNameDispatchingControllerWithSuffix() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MethodNameDispatchingController.class)); + InternalPathMethodNameResolver methodNameResolver = new InternalPathMethodNameResolver(); + methodNameResolver.setSuffix("Handle"); + RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class); + adapterDef.getPropertyValues().addPropertyValue("methodNameResolver", methodNameResolver); + wac.registerBeanDefinition("handlerAdapter", adapterDef); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/my.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myOther.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myOtherView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/myLang.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myLangView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/mySurprise.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("mySurpriseView", response.getContentAsString()); + } + + public void testControllerClassNamePlusMethodNameDispatchingController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + RootBeanDefinition mapping = new RootBeanDefinition(ControllerClassNameHandlerMapping.class); + mapping.getPropertyValues().addPropertyValue("excludedPackages", null); + wac.registerBeanDefinition("handlerMapping", mapping); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MethodNameDispatchingController.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/methodnamedispatching/myHandle"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/methodnamedispatching/myOtherHandle.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myOtherView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/methodnamedispatching/myLangHandle.x"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myLangView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/methodnamedispatching/mySurpriseHandle.y"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("mySurpriseView", response.getContentAsString()); + } + + public void testPostMethodNameDispatchingController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyPostMethodNameDispatchingController.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myHandle.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals(405, response.getStatus()); + + request = new MockHttpServletRequest("POST", "/myUnknownHandle.do"); + request.addParameter("myParam", "myValue"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals(404, response.getStatus()); + + request = new MockHttpServletRequest("POST", "/myHandle.do"); + request.addParameter("myParam", "myValue"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/myOtherHandle.do"); + request.addParameter("myParam", "myValue"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myOtherView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/myLangHandle.do"); + request.addParameter("myParam", "myValue"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myLangView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/mySurpriseHandle.do"); + request.addParameter("myParam", "myValue"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("mySurpriseView", response.getContentAsString()); + } + + public void testRelativePathDispatchingController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyRelativePathDispatchingController.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myApp/myHandle"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myApp/myOther"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myOtherView", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myApp/myLang"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myLangView", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myApp/surprise.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("mySurpriseView", response.getContentAsString()); + } + + public void testNullCommandController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyNullCommandController.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath"); + request.setUserPrincipal(new OtherPrincipal()); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + } + + public void testEquivalentMappingsWithSameMethodName() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(ChildController.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/child/test"); + request.addParameter("childId", "100"); + MockHttpServletResponse response = new MockHttpServletResponse(); + try { + servlet.service(request, response); + } + catch (NestedServletException ex) { + assertTrue(ex.getCause() instanceof IllegalStateException); + assertTrue(ex.getCause().getMessage().contains("doGet")); + } + } + + + @RequestMapping("/myPath.do") + private static class MyController extends AbstractController { + + protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { + response.getWriter().write("test"); + return null; + } + } + + + private static class BaseController { + + @RequestMapping(method = RequestMethod.GET) + public void myPath2(HttpServletResponse response) throws IOException { + response.getWriter().write("test"); + } + } + + + @Controller + private static class MyAdaptedController { + + @RequestMapping("/myPath1.do") + public void myHandle(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.getWriter().write("test"); + } + + @RequestMapping("/myPath2.do") + public void myHandle(@RequestParam("param1") String p1, @RequestParam("param2") int p2, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + p1 + "-" + p2); + } + + @RequestMapping("/myPath3") + public void myHandle(TestBean tb, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge()); + } + + @RequestMapping("/myPath4.do") + public void myHandle(TestBean tb, Errors errors, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode()); + } + } + + + @Controller + @RequestMapping("/*.do") + private static class MyAdaptedController2 { + + @RequestMapping + public void myHandle(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.getWriter().write("test"); + } + + @RequestMapping("/myPath2.do") + public void myHandle(@RequestParam("param1") String p1, int param2, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + p1 + "-" + param2); + } + + @RequestMapping("/myPath3") + public void myHandle(TestBean tb, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge()); + } + + @RequestMapping("/myPath4.*") + public void myHandle(TestBean tb, Errors errors, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode()); + } + } + + + @Controller + private static class MyAdaptedControllerBase { + + @RequestMapping("/myPath2.do") + public void myHandle(@RequestParam("param1") T p1, int param2, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + p1 + "-" + param2); + } + + @InitBinder + public void initBinder(@RequestParam("param1") T p1, int param2) { + } + + @ModelAttribute + public void modelAttribute(@RequestParam("param1") T p1, int param2) { + } + } + + + @RequestMapping("/*.do") + private static class MyAdaptedController3 extends MyAdaptedControllerBase { + + @RequestMapping + public void myHandle(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.getWriter().write("test"); + } + + @Override + public void myHandle(@RequestParam("param1") String p1, int param2, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + p1 + "-" + param2); + } + + @RequestMapping("/myPath3") + public void myHandle(TestBean tb, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge()); + } + + @RequestMapping("/myPath4.*") + public void myHandle(TestBean tb, Errors errors, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode()); + } + + @InitBinder + public void initBinder(@RequestParam("param1") String p1, int param2) { + } + + @ModelAttribute + public void modelAttribute(@RequestParam("param1") String p1, int param2) { + } + } + + + @Controller + @RequestMapping(method = RequestMethod.GET) + private static class EmptyParameterListHandlerMethodController { + + static boolean called; + + @RequestMapping("/emptyParameterListHandler") + public void emptyParameterListHandler() { + EmptyParameterListHandlerMethodController.called = true; + } + + @RequestMapping("/nonEmptyParameterListHandler") + public void nonEmptyParameterListHandler(HttpServletResponse response) { + } + } + + + @Controller + public static class MyFormController { + + @ModelAttribute("testBeanList") + public List getTestBeans() { + List list = new LinkedList(); + list.add(new TestBean("tb1")); + list.add(new TestBean("tb2")); + return list; + } + + @RequestMapping("/myPath.do") + public String myHandle(@ModelAttribute("myCommand") TestBean tb, BindingResult errors, ModelMap model) { + if (!model.containsKey("myKey")) { + model.addAttribute("myKey", "myValue"); + } + return "myView"; + } + } + + + @Controller + public static class MyModelFormController { + + @ModelAttribute + public List getTestBeans() { + List list = new LinkedList(); + list.add(new TestBean("tb1")); + list.add(new TestBean("tb2")); + return list; + } + + @RequestMapping("/myPath.do") + public String myHandle(@ModelAttribute("myCommand") TestBean tb, BindingResult errors, Model model) { + if (!model.containsAttribute("myKey")) { + model.addAttribute("myKey", "myValue"); + } + return "myView"; + } + } + + + @Controller + private static class MyCommandProvidingFormController extends MyFormController { + + @SuppressWarnings("unused") + @ModelAttribute("myCommand") + private TestBean createTestBean( + @RequestParam T defaultName, Map model, @RequestParam Date date) { + model.put("myKey", "myOriginalValue"); + return new TestBean(defaultName.getClass().getSimpleName() + ":" + defaultName.toString()); + } + + @RequestMapping("/myPath.do") + public String myHandle(@ModelAttribute("myCommand") TestBean tb, BindingResult errors, ModelMap model) { + return super.myHandle(tb, errors, model); + } + + @RequestMapping("/myOtherPath.do") + public String myOtherHandle(TB tb, BindingResult errors, ExtendedModelMap model, MySpecialArg arg) { + TestBean tbReal = (TestBean) tb; + tbReal.setName("myName"); + assertTrue(model.get("ITestBean") instanceof DerivedTestBean); + assertNotNull(arg); + return super.myHandle(tbReal, errors, model); + } + + @RequestMapping("/myThirdPath.do") + public String myThirdHandle(TB tb, Model model) { + model.addAttribute("testBean", new TestBean("special", 99)); + return "myView"; + } + + @ModelAttribute + protected TB2 getModelAttr() { + return (TB2) new DerivedTestBean(); + } + } + + + private static class MySpecialArg { + + public MySpecialArg(String value) { + } + } + + + @Controller + private static class MyTypedCommandProvidingFormController + extends MyCommandProvidingFormController { + } + + + @Controller + private static class MyBinderInitializingCommandProvidingFormController extends MyCommandProvidingFormController { + + @SuppressWarnings("unused") + @InitBinder + private void initBinder(WebDataBinder binder) { + binder.initBeanPropertyAccess(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + dateFormat.setLenient(false); + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); + } + } + + + @Controller + private static class MySpecificBinderInitializingCommandProvidingFormController extends MyCommandProvidingFormController { + + @SuppressWarnings("unused") + @InitBinder({"myCommand", "date"}) + private void initBinder(WebDataBinder binder, String date, @RequestParam("date") String[] date2) { + assertEquals("2007-10-02", date); + assertEquals(1, date2.length); + assertEquals("2007-10-02", date2[0]); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + dateFormat.setLenient(false); + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); + } + } + + + private static class MyWebBindingInitializer implements WebBindingInitializer { + + public void initBinder(WebDataBinder binder, WebRequest request) { + assertNotNull(request.getLocale()); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + dateFormat.setLenient(false); + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); + } + } + + + private static class MySpecialArgumentResolver implements WebArgumentResolver { + + public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) { + if (methodParameter.getParameterType().equals(MySpecialArg.class)) { + return new MySpecialArg("myValue"); + } + return UNRESOLVED; + } + } + + + @Controller + @RequestMapping("/myPath.do") + private static class MyParameterDispatchingController { + + @Autowired + private ServletContext servletContext; + + @Autowired + private ServletConfig servletConfig; + + @Autowired + private HttpSession session; + + @Autowired + private HttpServletRequest request; + + @RequestMapping + public void myHandle(HttpServletResponse response, HttpServletRequest request) throws IOException { + if (this.servletContext == null || this.servletConfig == null || this.session == null || this.request == null) { + throw new IllegalStateException(); + } + response.getWriter().write("myView"); + request.setAttribute("servletContext", this.servletContext); + request.setAttribute("servletConfig", this.servletConfig); + request.setAttribute("session", this.session); + request.setAttribute("request", this.request); + } + + @RequestMapping(params = {"view", "!lang"}) + public void myOtherHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myOtherView"); + } + + @RequestMapping(method = RequestMethod.GET, params = {"view=my", "lang=de"}) + public void myLangHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myLangView"); + } + + @RequestMapping(method = {RequestMethod.POST, RequestMethod.GET}, params = "surprise") + public void mySurpriseHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("mySurpriseView"); + } + } + + + @Controller + @RequestMapping(value = "/*.do", method = RequestMethod.POST, params = "myParam=myValue") + private static class MyPostMethodNameDispatchingController extends MethodNameDispatchingController { + + } + + + @Controller + @RequestMapping("/myApp/*") + private static class MyRelativePathDispatchingController { + + @RequestMapping + public void myHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myView"); + } + + @RequestMapping("*Other") + public void myOtherHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myOtherView"); + } + + @RequestMapping("myLang") + public void myLangHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myLangView"); + } + + @RequestMapping("surprise") + public void mySurpriseHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("mySurpriseView"); + } + } + + + @Controller + private static class MyNullCommandController { + + @ModelAttribute + public TestBean getTestBean() { + return null; + } + + @ModelAttribute + public Principal getPrincipal() { + return new TestPrincipal(); + } + + @RequestMapping("/myPath") + public void handle(@ModelAttribute TestBean testBean, Errors errors, + @ModelAttribute TestPrincipal modelPrinc, OtherPrincipal requestPrinc, Writer writer) throws IOException { + assertNull(testBean); + assertNotNull(modelPrinc); + assertNotNull(requestPrinc); + assertFalse(errors.hasErrors()); + errors.reject("myCode"); + writer.write("myView"); + } + } + + + private static class TestPrincipal implements Principal { + + public String getName() { + return "test"; + } + } + + + private static class OtherPrincipal implements Principal { + + public String getName() { + return "other"; + } + } + + + private static class TestViewResolver implements ViewResolver { + + public View resolveViewName(final String viewName, Locale locale) throws Exception { + return new View() { + public String getContentType() { + return null; + } + @SuppressWarnings({"unchecked", "deprecation"}) + public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { + TestBean tb = (TestBean) model.get("testBean"); + if (tb == null) { + tb = (TestBean) model.get("myCommand"); + } + if (tb.getName().endsWith("myDefaultName")) { + assertTrue(tb.getDate().getYear() == 107); + } + Errors errors = (Errors) model.get(BindingResult.MODEL_KEY_PREFIX + "testBean"); + if (errors == null) { + errors = (Errors) model.get(BindingResult.MODEL_KEY_PREFIX + "myCommand"); + } + if (errors.hasFieldErrors("date")) { + throw new IllegalStateException(); + } + if (model.containsKey("ITestBean")) { + assertTrue(model.get(BindingResult.MODEL_KEY_PREFIX + "ITestBean") instanceof Errors); + } + List testBeans = (List) model.get("testBeanList"); + if (errors.hasFieldErrors("age")) { + response.getWriter().write(viewName + "-" + tb.getName() + "-" + errors.getFieldError("age").getCode() + + "-" + testBeans.get(0).getName() + "-" + model.get("myKey")); + } + else { + response.getWriter().write(viewName + "-" + tb.getName() + "-" + tb.getAge() + "-" + + errors.getFieldValue("name") + "-" + errors.getFieldValue("age")); + } + } + }; + } + } + + + public static class ParentController { + + @RequestMapping(method = RequestMethod.GET) + public void doGet(HttpServletRequest req, HttpServletResponse resp) { + } + } + + + @Controller + @RequestMapping("/child/test") + public static class ChildController extends ParentController { + + @RequestMapping(method = RequestMethod.GET) + public void doGet(HttpServletRequest req, HttpServletResponse resp, @RequestParam("childId") String id) { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/WelcomeController.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/WelcomeController.java new file mode 100644 index 00000000000..5b1febae294 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/WelcomeController.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2006 the original author 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.web.servlet.mvc.annotation; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Juergen Hoeller + */ +@Controller +public class WelcomeController { + + @RequestMapping + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { + return new ModelAndView("welcomeView"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/class-mapping.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/class-mapping.xml new file mode 100644 index 00000000000..bd73342dc4e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/annotation/class-mapping.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/OptionTagEnumTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/OptionTagEnumTests.java new file mode 100644 index 00000000000..208f63b4baa --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/OptionTagEnumTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.tags.form; + +import javax.servlet.jsp.tagext.BodyTag; +import javax.servlet.jsp.tagext.Tag; + +import org.springframework.beans.CustomEnum; +import org.springframework.beans.GenericBean; +import org.springframework.web.servlet.support.BindStatus; + +/** + * @author Juergen Hoeller + */ +public class OptionTagEnumTests extends AbstractHtmlElementTagTests { + + private OptionTag tag; + + protected void onSetUp() { + this.tag = new OptionTag() { + protected TagWriter createTagWriter() { + return new TagWriter(getWriter()); + } + }; + this.tag.setParent(new SelectTag()); + this.tag.setPageContext(getPageContext()); + } + + public void testWithJavaEnum() throws Exception { + GenericBean testBean = new GenericBean(); + testBean.setCustomEnum(CustomEnum.VALUE_1); + getPageContext().getRequest().setAttribute("testBean", testBean); + getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.customEnum", false)); + + this.tag.setValue("VALUE_1"); + + int result = this.tag.doStartTag(); + assertEquals(BodyTag.EVAL_BODY_BUFFERED, result); + result = this.tag.doEndTag(); + assertEquals(Tag.EVAL_PAGE, result); + + String output = getWriter().toString(); + + assertOptionTagOpened(output); + assertOptionTagClosed(output); + assertContainsAttribute(output, "value", "VALUE_1"); + assertContainsAttribute(output, "selected", "selected"); + } + + private void assertOptionTagOpened(String output) { + assertTrue(output.startsWith("")); + } + +}